From c210ca5b4d5c7fd5de0a5c15f3fc66d97a97caad Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Tue, 13 Oct 2015 19:59:02 +0300 Subject: [PATCH] Additional correctness check for noinline & crossinline #KT-9567 Fixed --- .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../kotlin/resolve/InlineParameterChecker.kt | 53 +++++++++++++++++++ .../kotlin/resolve/TargetPlatform.kt | 1 + .../tests/modifiers/inlineParameters.kt | 10 ++++ .../tests/modifiers/inlineParameters.txt | 6 +++ .../checkers/JetDiagnosticsTestGenerated.java | 6 +++ 7 files changed, 78 insertions(+) create mode 100644 compiler/frontend/src/org/jetbrains/kotlin/resolve/InlineParameterChecker.kt create mode 100644 compiler/testData/diagnostics/tests/modifiers/inlineParameters.kt create mode 100644 compiler/testData/diagnostics/tests/modifiers/inlineParameters.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 97bc11a261c..09a664d67a9 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -125,6 +125,7 @@ public interface Errors { DiagnosticFactory2 REDUNDANT_MODIFIER_FOR_TARGET = DiagnosticFactory2.create(WARNING); DiagnosticFactory2 WRONG_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(ERROR); DiagnosticFactory2 DEPRECATED_MODIFIER_CONTAINING_DECLARATION = DiagnosticFactory2.create(WARNING); + DiagnosticFactory1 ILLEGAL_INLINE_PARAMETER_MODIFIER = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 WRONG_ANNOTATION_TARGET = DiagnosticFactory1.create(ERROR); DiagnosticFactory2 WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET = DiagnosticFactory2.create(ERROR); DiagnosticFactory0 REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 011d4c82272..08c46fc6a46 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -132,6 +132,7 @@ public class DefaultErrorMessages { MAP.put(REDUNDANT_MODIFIER_FOR_TARGET, "Modifier ''{0}'' is redundant for ''{1}''", TO_STRING, TO_STRING); MAP.put(WRONG_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is not applicable inside ''{1}''", TO_STRING, TO_STRING); MAP.put(DEPRECATED_MODIFIER_CONTAINING_DECLARATION, "Modifier ''{0}'' is deprecated inside ''{1}''", TO_STRING, TO_STRING); + MAP.put(ILLEGAL_INLINE_PARAMETER_MODIFIER, "Modifier ''{0}'' is allowed only for function parameters of an inline function", TO_STRING); MAP.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING); MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET, "This annotation is not applicable to target ''{0}'' and use site target ''@{1}''", TO_STRING, TO_STRING); MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/InlineParameterChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/InlineParameterChecker.kt new file mode 100644 index 00000000000..d40bfa0535f --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/InlineParameterChecker.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2015 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.KotlinBuiltIns +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.lexer.JetModifierKeywordToken +import org.jetbrains.kotlin.lexer.JetTokens +import org.jetbrains.kotlin.psi.JetDeclaration +import org.jetbrains.kotlin.psi.JetFunction +import org.jetbrains.kotlin.psi.JetParameter + +object InlineParameterChecker : DeclarationChecker { + override fun check(declaration: JetDeclaration, + descriptor: DeclarationDescriptor, + diagnosticHolder: DiagnosticSink, + bindingContext: BindingContext + ) { + if (declaration is JetFunction) { + val inline = declaration.hasModifier(JetTokens.INLINE_KEYWORD) + for (parameter in declaration.valueParameters) { + val parameterDescriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, parameter) + if (!inline || (parameterDescriptor != null && !KotlinBuiltIns.isFunctionOrExtensionFunctionType(parameterDescriptor.type))) { + parameter.reportIncorrectInline(JetTokens.NOINLINE_KEYWORD, diagnosticHolder) + parameter.reportIncorrectInline(JetTokens.CROSSINLINE_KEYWORD, diagnosticHolder) + } + } + } + } + + private fun JetParameter.reportIncorrectInline(modifierToken: JetModifierKeywordToken, diagnosticHolder: DiagnosticSink) { + val modifier = modifierList?.getModifier(modifierToken) + modifier?.let { + diagnosticHolder.report(Errors.ILLEGAL_INLINE_PARAMETER_MODIFIER.on(modifier, modifierToken)) + } + } +} \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt index 13cb5bf822b..35998441536 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/TargetPlatform.kt @@ -51,6 +51,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf( DataClassAnnotationChecker(), ConstModifierChecker, UnderscoreChecker, + InlineParameterChecker, OperatorModifierChecker(), InfixModifierChecker()) diff --git a/compiler/testData/diagnostics/tests/modifiers/inlineParameters.kt b/compiler/testData/diagnostics/tests/modifiers/inlineParameters.kt new file mode 100644 index 00000000000..7195b64ef53 --- /dev/null +++ b/compiler/testData/diagnostics/tests/modifiers/inlineParameters.kt @@ -0,0 +1,10 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +inline fun foo(noinline x: Int) {} + +inline fun bar(y: Int, crossinline x: String) {} + +fun gav(noinline x: (Int) -> Unit, crossinline y: (String) -> Int) {} + +inline fun correct(noinline x: (Int) -> Unit, crossinline y: (String) -> Int) {} + diff --git a/compiler/testData/diagnostics/tests/modifiers/inlineParameters.txt b/compiler/testData/diagnostics/tests/modifiers/inlineParameters.txt new file mode 100644 index 00000000000..31c9525c8c3 --- /dev/null +++ b/compiler/testData/diagnostics/tests/modifiers/inlineParameters.txt @@ -0,0 +1,6 @@ +package + +@kotlin.inline() public fun bar(/*0*/ y: kotlin.Int, /*1*/ @kotlin.crossinline() x: kotlin.String): kotlin.Unit +@kotlin.inline() public fun correct(/*0*/ @kotlin.noinline() x: (kotlin.Int) -> kotlin.Unit, /*1*/ @kotlin.crossinline() y: (kotlin.String) -> kotlin.Int): kotlin.Unit +@kotlin.inline() public fun foo(/*0*/ @kotlin.noinline() x: kotlin.Int): kotlin.Unit +public fun gav(/*0*/ @kotlin.noinline() x: (kotlin.Int) -> kotlin.Unit, /*1*/ @kotlin.crossinline() y: (kotlin.String) -> kotlin.Int): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 67e228f6230..649e47d162c 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -9430,6 +9430,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("inlineParameters.kt") + public void testInlineParameters() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/inlineParameters.kt"); + doTest(fileName); + } + @TestMetadata("internalInInterface.kt") public void testInternalInInterface() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/modifiers/internalInInterface.kt");