From 75ab0dd509a4f5b48d047a08f78e0161f980b895 Mon Sep 17 00:00:00 2001 From: Andrey Breslav Date: Thu, 17 Dec 2015 20:30:12 +0300 Subject: [PATCH] 'sealed' reserved in front of `when` --- .../org/jetbrains/kotlin/cfg/WhenChecker.java | 4 ++ .../org/jetbrains/kotlin/psi/KtPsiUtil.java | 19 ++++++++++ .../jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt | 9 ++++- .../PatternMatchingTypingVisitor.java | 1 + .../tests/when/ReservedExhaustiveWhen.kt | 37 +++++++++++++++++++ .../tests/when/ReservedExhaustiveWhen.txt | 6 +++ .../checkers/DiagnosticsTestGenerated.java | 6 +++ 7 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 compiler/testData/diagnostics/tests/when/ReservedExhaustiveWhen.kt create mode 100644 compiler/testData/diagnostics/tests/when/ReservedExhaustiveWhen.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java index e3e79e5a315..a8c63c543e5 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/WhenChecker.java @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.Modality; import org.jetbrains.kotlin.diagnostics.Errors; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.BindingTrace; import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils; @@ -283,4 +284,7 @@ public final class WhenChecker { } } + public static void checkReservedPrefix(@NotNull BindingTrace trace, @NotNull KtWhenExpression expression) { + KtPsiUtilKt.checkReservedPrefixWord(trace, expression.getWhenKeyword(), "sealed", "sealed when"); + } } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java index 7050d1af2a0..001bdd76780 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtPsiUtil.java @@ -599,6 +599,25 @@ public class KtPsiUtil { return PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class, PsiComment.class); } + @Nullable + public static PsiElement prevLeafIgnoringWhitespaceAndComments(@NotNull PsiElement element) { + PsiElement prev = PsiTreeUtil.prevLeaf(element, true); + while (prev != null && KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET.contains(prev.getNode().getElementType())) { + prev = PsiTreeUtil.prevLeaf(prev, true); + } + return prev; + } + + @Nullable + public static PsiElement getPreviousWord(@NotNull PsiElement element, @NotNull String word) { + PsiElement prev = prevLeafIgnoringWhitespaceAndComments(element); + if (prev != null && prev.getNode().getElementType() == KtTokens.IDENTIFIER && word.equals(prev.getText())) { + return prev; + } + + return null; + } + public static final Predicate ANY_JET_ELEMENT = new Predicate() { @Override public boolean apply(@Nullable KtElement input) { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt index 8dc14346b61..de7efea1f23 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/psiUtil/ktPsiUtil.kt @@ -25,6 +25,8 @@ import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.stubs.StubElement import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.KtNodeTypes +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.Name @@ -36,7 +38,6 @@ import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch import org.jetbrains.kotlin.types.expressions.OperatorConventions import java.util.* import kotlin.test.assertTrue -import kotlin.text.Regex // NOTE: in this file we collect only Kotlin-specific methods working with PSI and not modifying it @@ -431,4 +432,10 @@ private val BAD_NEIGHBOUR_FOR_SIMPLE_TEMPLATE_ENTRY_PATTERN = Regex("[a-zA-Z0-9_ fun canPlaceAfterSimpleNameEntry(element: PsiElement?): Boolean { val entryText = element?.text ?: return true return !BAD_NEIGHBOUR_FOR_SIMPLE_TEMPLATE_ENTRY_PATTERN.matches(entryText) +} + +fun checkReservedPrefixWord(sink: DiagnosticSink, element: PsiElement, word: String, message: String) { + KtPsiUtil.getPreviousWord(element, word)?.let { + sink.report(Errors.UNSUPPORTED.on(it, message)) + } } \ No newline at end of file diff --git a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java index 45082bfc797..e32618b4451 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/types/expressions/PatternMatchingTypingVisitor.java @@ -75,6 +75,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor { public KotlinTypeInfo visitWhenExpression(KtWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) { WhenChecker.checkDeprecatedWhenSyntax(contextWithExpectedType.trace, expression); + WhenChecker.checkReservedPrefix(contextWithExpectedType.trace, expression); components.dataFlowAnalyzer.recordExpectedType(contextWithExpectedType.trace, expression, contextWithExpectedType.expectedType); diff --git a/compiler/testData/diagnostics/tests/when/ReservedExhaustiveWhen.kt b/compiler/testData/diagnostics/tests/when/ReservedExhaustiveWhen.kt new file mode 100644 index 00000000000..dfbb7a98d87 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/ReservedExhaustiveWhen.kt @@ -0,0 +1,37 @@ +// !DIAGNOSTICS: -UNUSED_PARAMETER + +infix fun Any.sealed(a: Any?) {} + +val x = 1 sealed when (1) { + 1 -> 1 + else -> 2 +} + +val x1 = 1 sealed /**/ when (1) { + 1 -> 1 + else -> 2 +} + +fun foo() { + sealed when { + else -> {} + } + + 1 sealed when { + else -> {} + } + + 1 sealed (when { + else -> {} + }) + + 1 + sealed when { + else -> {} + } + + 1 sealed + when { + else -> {} + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/when/ReservedExhaustiveWhen.txt b/compiler/testData/diagnostics/tests/when/ReservedExhaustiveWhen.txt new file mode 100644 index 00000000000..5fb306e4970 --- /dev/null +++ b/compiler/testData/diagnostics/tests/when/ReservedExhaustiveWhen.txt @@ -0,0 +1,6 @@ +package + +public val x: kotlin.Unit +public val x1: kotlin.Unit +public fun foo(): kotlin.Unit +public infix fun kotlin.Any.sealed(/*0*/ a: kotlin.Any?): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 38fcdc7a00f..9b94afdc685 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -18186,6 +18186,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest { doTest(fileName); } + @TestMetadata("ReservedExhaustiveWhen.kt") + public void testReservedExhaustiveWhen() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/ReservedExhaustiveWhen.kt"); + doTest(fileName); + } + @TestMetadata("When.kt") public void testWhen() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/When.kt");