Add custom applicability checks for suspend/coroutine modifiers

This commit is contained in:
Denis Zharkov
2016-05-26 19:00:53 +03:00
parent d760a2ec3b
commit b8d4d39f4d
22 changed files with 377 additions and 9 deletions
@@ -18,14 +18,17 @@ package org.jetbrains.kotlin.coroutines
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.TemporaryBindingTrace
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
import org.jetbrains.kotlin.types.expressions.FakeCallKind
@@ -77,10 +80,13 @@ fun FakeCallResolver.resolveCoroutineHandleResultCallIfNeeded(
val resolutionResults = resolveFakeCall(
context.replaceBindingTrace(temporaryBindingTrace), functionDescriptor.extensionReceiverParameter!!.value,
Name.identifier("handleResult"), callElement, callElement, FakeCallKind.OTHER,
OperatorNameConventions.COROUTINE_HANDLE_RESULT, callElement, callElement, FakeCallKind.OTHER,
listOf(firstArgument, continuation))
if (resolutionResults.isSuccess) {
context.trace.record(BindingContext.RETURN_HANDLE_RESULT_RESOLVED_CALL, callElement, resolutionResults.resultingCall)
}
}
fun KotlinType.isValidContinuation() =
(constructor.declarationDescriptor as? ClassDescriptor)?.fqNameUnsafe == DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.toUnsafe()
@@ -622,6 +622,8 @@ public interface Errors {
DiagnosticFactory2<PsiElement, FunctionDescriptor, String> OPERATOR_MODIFIER_REQUIRED = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<KtOperationReferenceExpression, FunctionDescriptor, String> INFIX_MODIFIER_REQUIRED = DiagnosticFactory2.create(ERROR);
DiagnosticFactory2<PsiElement, KtModifierKeywordToken, String> INAPPLICABLE_MODIFIER = DiagnosticFactory2.create(ERROR);
// Labels
DiagnosticFactory0<KtSimpleNameExpression> LABEL_NAME_CLASH = DiagnosticFactory0.create(WARNING);
@@ -383,6 +383,8 @@ public class DefaultErrorMessages {
MAP.put(OPERATOR_MODIFIER_REQUIRED, "''operator'' modifier is required on ''{0}'' in ''{1}''", NAME, STRING);
MAP.put(INFIX_MODIFIER_REQUIRED, "''infix'' modifier is required on ''{0}'' in ''{1}''", NAME, STRING);
MAP.put(INAPPLICABLE_MODIFIER, "''{0}'' modifier is inapplicable. The reason is that {1}", TO_STRING, STRING);
MAP.put(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY,
"Returns are not allowed for functions with expression body. Use block body in '{...}'");
MAP.put(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY, "A 'return' expression required in a function with a block body ('{...}')");
@@ -81,7 +81,7 @@ object ModifierCheckerCore {
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
COROUTINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
SUSPEND_KEYWORD to EnumSet.of(FUNCTION),
SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION),
EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER),
ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS),
CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
@@ -0,0 +1,113 @@
/*
* Copyright 2010-2016 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.builtins.getReceiverTypeFromFunctionType
import org.jetbrains.kotlin.builtins.getReturnTypeFromFunctionType
import org.jetbrains.kotlin.builtins.isExtensionFunctionType
import org.jetbrains.kotlin.coroutines.isValidContinuation
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.incremental.KotlinLookupLocation
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.sure
object SuspendModifierChecker : DeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
val functionDescriptor = descriptor as? FunctionDescriptor ?: return
if (!functionDescriptor.isSuspend) return
val suspendModifierElement = declaration.modifierList?.getModifier(KtTokens.SUSPEND_KEYWORD).sure { "${declaration.text}" }
fun report(message: String) {
diagnosticHolder.report(Errors.INAPPLICABLE_MODIFIER.on(suspendModifierElement, KtTokens.SUSPEND_KEYWORD, message))
}
if (functionDescriptor.isInline) {
report("inline suspend functions are not supported")
return
}
val isValidContinuation = functionDescriptor.valueParameters.lastOrNull()?.type?.isValidContinuation() ?: false
if (!isValidContinuation) {
report("last parameter of suspend function should have a type of Continuation<T>")
return
}
}
}
object CoroutineModifierChecker : DeclarationChecker {
override fun check(
declaration: KtDeclaration,
descriptor: DeclarationDescriptor,
diagnosticHolder: DiagnosticSink,
bindingContext: BindingContext
) {
val functionDescriptor = descriptor as? FunctionDescriptor ?: return
if (declaration !is KtDeclarationWithBody) return
val location = KotlinLookupLocation(declaration)
for ((parameterDescriptor, parameterDeclaration) in functionDescriptor.valueParameters.zip(declaration.valueParameters)) {
if (!parameterDescriptor.isCoroutine) continue
val coroutineModifier = parameterDeclaration.modifierList?.getModifier(KtTokens.COROUTINE_KEYWORD) ?: continue
fun report(message: String) {
diagnosticHolder.report(Errors.INAPPLICABLE_MODIFIER.on(coroutineModifier, KtTokens.COROUTINE_KEYWORD, message))
}
if (!parameterDescriptor.type.isExtensionFunctionType) {
report("parameter should have function type with extension like 'Controller.() -> Continuation<Unit>'")
continue
}
val returnType = getReturnTypeFromFunctionType(parameterDescriptor.type)
if (returnType.isMarkedNullable || !returnType.isValidContinuation() || !returnType.arguments.single().type.isUnit()) {
report("parameter should have function type like 'Controller.() -> Continuation<Unit>' (Continuation<Unit> for return type is necessary)")
continue
}
if (functionDescriptor.isInline && !parameterDescriptor.isNoinline) {
report("coroutine parameter of inline function should be marked as 'noinline'")
continue
}
val controller = getReceiverTypeFromFunctionType(parameterDescriptor.type)!!
val handleResultFunctions =
controller.memberScope
.getContributedFunctions(OperatorNameConventions.COROUTINE_HANDLE_RESULT, location)
.filter { it.isOperator }
if (handleResultFunctions.size > 1) {
report("only one operator handleResult should be declared for controller, but ${handleResultFunctions.size} found")
continue
}
}
}
}
@@ -63,7 +63,9 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
UnderscoreChecker,
InlineParameterChecker,
OperatorModifierChecker(),
InfixModifierChecker())
InfixModifierChecker(),
SuspendModifierChecker,
CoroutineModifierChecker)
private val DEFAULT_CALL_CHECKERS = listOf(CapturingInClosureChecker(), InlineCheckerWrapper(), ReifiedTypeParameterSubstitutionChecker(),
SafeCallChecker(), InvokeConventionChecker(), CallReturnsArrayOfNothingChecker(),
@@ -0,0 +1,45 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE
class Controller
class A(coroutine c: Controller.() -> Continuation<Unit>, y: Int) {
var x: String = ""
set(<!INAPPLICABLE_MODIFIER!>coroutine<!> x) {
}
constructor(coroutine c: Controller.() -> Continuation<Unit>) : this(c, 1)
constructor(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Continuation<Nothing>, y: String) : <!NONE_APPLICABLE!>this<!>(c, 2)
}
fun valid(coroutine c: Controller.() -> Continuation<Unit>) {
}
fun noFunctionType(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Unit) {
}
fun noExtensionFunction(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: (Controller) -> Continuation<Unit>) {
}
fun nullableReturnType(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Continuation<Unit>?) {
}
fun wrongReturnType(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Collection<Unit>) {
}
fun notUnitContinuation(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Continuation<Int>) {
}
inline fun inlineBuilder(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: Controller.() -> Continuation<Unit>) {
}
inline fun inlineBuilderNoInlineCoroutine(coroutine noinline c: Controller.() -> Continuation<Unit>) {
}
@@ -0,0 +1,27 @@
package
public inline fun inlineBuilder(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
public inline fun inlineBuilderNoInlineCoroutine(/*0*/ noinline coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
public fun noExtensionFunction(/*0*/ coroutine c: (Controller) -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
public fun noFunctionType(/*0*/ coroutine c: kotlin.Unit): kotlin.Unit
public fun notUnitContinuation(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Int>): kotlin.Unit
public fun nullableReturnType(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>?): kotlin.Unit
public fun valid(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
public fun wrongReturnType(/*0*/ coroutine c: Controller.() -> kotlin.collections.Collection<kotlin.Unit>): kotlin.Unit
public final class A {
public constructor A(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Nothing>, /*1*/ y: kotlin.String)
public constructor A(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>)
public constructor A(/*0*/ coroutine c: Controller.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*1*/ y: kotlin.Int)
public final var x: kotlin.String
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 class Controller {
public constructor Controller()
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
}
@@ -22,7 +22,7 @@ fun emptyBuilder(coroutine c: EmptyController.() -> Continuation<Unit>) = 1
fun <T> manyArgumentsBuilder(
coroutine c1: UnitController.() -> Continuation<Unit>,
coroutine c2: GenericController<T>.() -> Continuation<Unit>,
coroutine c3: IntController.() -> Continuation<Int>
coroutine c3: IntController.() -> Continuation<Unit>
):T = null!!
fun severalParamsInLambda(coroutine c: UnitController.(String, Int) -> Continuation<Unit>) {}
@@ -4,7 +4,7 @@ public fun builder(/*0*/ coroutine c: IntController.() -> kotlin.coroutines.Cont
public fun emptyBuilder(/*0*/ coroutine c: EmptyController.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Int
public fun foo(): kotlin.Unit
public fun </*0*/ T> genericBuilder(/*0*/ coroutine c: GenericController<T>.() -> kotlin.coroutines.Continuation<kotlin.Unit>): T
public fun </*0*/ T> manyArgumentsBuilder(/*0*/ coroutine c1: UnitController.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*1*/ coroutine c2: GenericController<T>.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*2*/ coroutine c3: IntController.() -> kotlin.coroutines.Continuation<kotlin.Int>): T
public fun </*0*/ T> manyArgumentsBuilder(/*0*/ coroutine c1: UnitController.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*1*/ coroutine c2: GenericController<T>.() -> kotlin.coroutines.Continuation<kotlin.Unit>, /*2*/ coroutine c3: IntController.() -> kotlin.coroutines.Continuation<kotlin.Unit>): T
public fun severalParamsInLambda(/*0*/ coroutine c: UnitController.(kotlin.String, kotlin.Int) -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
public fun unitBuilder(/*0*/ coroutine c: UnitController.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Int
@@ -0,0 +1,16 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
interface A {
operator fun handleResult(x: Int, y: Continuation<Nothing>) {}
}
interface B {
operator fun handleResult(x: String, y: Continuation<Nothing>) {}
}
class C : A, B {
// multiple handleResults
}
fun builder1(coroutine c: A.() -> Continuation<Unit>) {}
fun builder2(coroutine c: B.() -> Continuation<Unit>) {}
fun builder3(<!INAPPLICABLE_MODIFIER!>coroutine<!> c: C.() -> Continuation<Unit>) {}
@@ -0,0 +1,28 @@
package
public fun builder1(/*0*/ coroutine c: A.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
public fun builder2(/*0*/ coroutine c: B.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
public fun builder3(/*0*/ coroutine c: C.() -> kotlin.coroutines.Continuation<kotlin.Unit>): kotlin.Unit
public interface A {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open operator fun handleResult(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public interface B {
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open operator fun handleResult(/*0*/ x: kotlin.String, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class C : A, B {
public constructor C()
public open override /*2*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun handleResult(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun handleResult(/*0*/ x: kotlin.String, /*1*/ y: kotlin.coroutines.Continuation<kotlin.Nothing>): kotlin.Unit
public open override /*2*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*2*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -0,0 +1,26 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE
<!WRONG_MODIFIER_TARGET!>suspend<!> fun notMember(x: Continuation<Int>) {
}
class Controller {
suspend fun valid(x: Continuation<Int>) {
}
inline <!INAPPLICABLE_MODIFIER!>suspend<!> fun inlineFun(x: Continuation<Int>) {
}
<!INAPPLICABLE_MODIFIER!>suspend<!> fun noParams() {
}
<!INAPPLICABLE_MODIFIER!>suspend<!> fun wrongParam(x: Collection<Int>) {
}
<!INAPPLICABLE_MODIFIER!>suspend<!> fun starProjection(vararg x: Continuation<Any>) {
}
}
@@ -0,0 +1,15 @@
package
public suspend fun notMember(/*0*/ x: kotlin.coroutines.Continuation<kotlin.Int>): kotlin.Unit
public final class Controller {
public constructor Controller()
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 inline suspend fun inlineFun(/*0*/ x: kotlin.coroutines.Continuation<kotlin.Int>): kotlin.Unit
public final suspend fun noParams(): kotlin.Unit
public final suspend fun starProjection(/*0*/ vararg x: kotlin.coroutines.Continuation<kotlin.Any> /*kotlin.Array<out kotlin.coroutines.Continuation<kotlin.Any>>*/): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
public final suspend fun valid(/*0*/ x: kotlin.coroutines.Continuation<kotlin.Int>): kotlin.Unit
public final suspend fun wrongParam(/*0*/ x: kotlin.collections.Collection<kotlin.Int>): kotlin.Unit
}
@@ -3867,6 +3867,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/coroutines"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("coroutineApplicability.kt")
public void testCoroutineApplicability() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/coroutineApplicability.kt");
doTest(fileName);
}
@TestMetadata("irrelevantSuspendDeclarations.kt")
public void testIrrelevantSuspendDeclarations() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/irrelevantSuspendDeclarations.kt");
@@ -3879,12 +3885,24 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("manyHandleResults.kt")
public void testManyHandleResults() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/manyHandleResults.kt");
doTest(fileName);
}
@TestMetadata("nonLocalSuspension.kt")
public void testNonLocalSuspension() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/nonLocalSuspension.kt");
doTest(fileName);
}
@TestMetadata("suspendApplicability.kt")
public void testSuspendApplicability() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendApplicability.kt");
doTest(fileName);
}
@TestMetadata("suspendFunctions.kt")
public void testSuspendFunctions() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/coroutines/suspendFunctions.kt");
@@ -34,5 +34,4 @@ class B {
// EXIST: external
// EXIST: annotation class
// EXIST: const
// EXIST: suspend
// NOTHING_ELSE
@@ -38,5 +38,4 @@ var a : Int
// EXIST: external
// EXIST: annotation class
// EXIST: const
// EXIST: suspend
// NOTHING_ELSE
@@ -25,5 +25,4 @@ package Test
// EXIST: external
// EXIST: annotation class
// EXIST: const
// EXIST: suspend
// NOTHING_ELSE
-1
View File
@@ -24,5 +24,4 @@
// EXIST: external
// EXIST: annotation class
// EXIST: const
// EXIST: suspend
// NOTHING_ELSE
+34
View File
@@ -0,0 +1,34 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE
class Controller
fun valid(<info descr="null">coroutine</info> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Unit>) {
}
fun noFunctionType(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type with extension like 'Controller.() -> Continuation<Unit>'"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Unit) {
}
fun noExtensionFunction(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type with extension like 'Controller.() -> Continuation<Unit>'"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: (Controller) -> Continuation<Unit>) {
}
fun nullableReturnType(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type like 'Controller.() -> Continuation<Unit>' (Continuation<Unit> for return type is necessary)"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Unit>?) {
}
fun wrongReturnType(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type like 'Controller.() -> Continuation<Unit>' (Continuation<Unit> for return type is necessary)"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Collection<Unit>) {
}
fun notUnitContinuation(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that parameter should have function type like 'Controller.() -> Continuation<Unit>' (Continuation<Unit> for return type is necessary)"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Int>) {
}
<info descr="null">inline</info> fun inlineBuilder(<error descr="[INAPPLICABLE_MODIFIER] 'coroutine' modifier is inapplicable. The reason is that coroutine parameter of inline function should be marked as 'noinline'"><info descr="null">coroutine</info></error> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Unit>) {
}
<warning descr="[NOTHING_TO_INLINE] Expected performance impact of inlining 'public inline fun inlineBuilderNoInlineCoroutine(noinline coroutine c: Controller.() -> Continuation<Unit>): Unit defined in root package' can be insignificant. Inlining works best for functions with lambda parameters"><info descr="null">inline</info></warning> fun inlineBuilderNoInline<TYPO descr="Typo: In word 'Coroutine'">Coroutine</TYPO>(<info descr="null">coroutine</info> <info descr="null">noinline</info> <warning descr="[UNUSED_PARAMETER] Parameter 'c' is never used">c</warning>: Controller.() -> Continuation<Unit>) {
}
+26
View File
@@ -0,0 +1,26 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER -NOTHING_TO_INLINE
<error descr="[WRONG_MODIFIER_TARGET] Modifier 'suspend' is not applicable to 'top level function'"><info descr="null">suspend</info></error> fun notMember(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Continuation<Int>) {
}
class Controller {
<info descr="null">suspend</info> fun valid(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Continuation<Int>) {
}
<warning descr="[NOTHING_TO_INLINE] Expected performance impact of inlining 'public final inline suspend fun inlineFun(x: Continuation<Int>): Unit defined in Controller' can be insignificant. Inlining works best for functions with lambda parameters"><info descr="null">inline</info></warning> <error descr="[INAPPLICABLE_MODIFIER] 'suspend' modifier is inapplicable. The reason is that inline suspend functions are not supported"><info descr="null">suspend</info></error> fun inlineFun(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Continuation<Int>) {
}
<error descr="[INAPPLICABLE_MODIFIER] 'suspend' modifier is inapplicable. The reason is that last parameter of suspend function should have a type of Continuation<T>"><info descr="null">suspend</info></error> fun noParams() {
}
<error descr="[INAPPLICABLE_MODIFIER] 'suspend' modifier is inapplicable. The reason is that last parameter of suspend function should have a type of Continuation<T>"><info descr="null">suspend</info></error> fun wrongParam(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Collection<Int>) {
}
<info descr="null">suspend</info> fun starProjection(<warning descr="[UNUSED_PARAMETER] Parameter 'x' is never used">x</warning>: Continuation<*>) {
}
}
@@ -874,6 +874,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
doTestWithInfos(fileName);
}
@TestMetadata("coroutineApplicability.kt")
public void testCoroutineApplicability() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/coroutineApplicability.kt");
doTestWithInfos(fileName);
}
@TestMetadata("PropertiesWithBackingFields.kt")
public void testPropertiesWithBackingFields() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/PropertiesWithBackingFields.kt");
@@ -910,6 +916,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
doTestWithInfos(fileName);
}
@TestMetadata("suspendApplicability.kt")
public void testSuspendApplicability() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/suspendApplicability.kt");
doTestWithInfos(fileName);
}
@TestMetadata("Typos.kt")
public void testTypos() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/infos/Typos.kt");