'sealed' reserved in front of when
This commit is contained in:
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.descriptors.Modality;
|
|||||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens;
|
import org.jetbrains.kotlin.lexer.KtTokens;
|
||||||
import org.jetbrains.kotlin.psi.*;
|
import org.jetbrains.kotlin.psi.*;
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils;
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -599,6 +599,25 @@ public class KtPsiUtil {
|
|||||||
return PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class, PsiComment.class);
|
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<KtElement> ANY_JET_ELEMENT = new Predicate<KtElement>() {
|
public static final Predicate<KtElement> ANY_JET_ELEMENT = new Predicate<KtElement>() {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(@Nullable KtElement input) {
|
public boolean apply(@Nullable KtElement input) {
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import com.intellij.psi.PsiWhiteSpace
|
|||||||
import com.intellij.psi.stubs.StubElement
|
import com.intellij.psi.stubs.StubElement
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.KtNodeTypes
|
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.KtModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.Name
|
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 org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.test.assertTrue
|
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
|
// 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 {
|
fun canPlaceAfterSimpleNameEntry(element: PsiElement?): Boolean {
|
||||||
val entryText = element?.text ?: return true
|
val entryText = element?.text ?: return true
|
||||||
return !BAD_NEIGHBOUR_FOR_SIMPLE_TEMPLATE_ENTRY_PATTERN.matches(entryText)
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
@@ -75,6 +75,7 @@ public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
public KotlinTypeInfo visitWhenExpression(KtWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
|
public KotlinTypeInfo visitWhenExpression(KtWhenExpression expression, ExpressionTypingContext contextWithExpectedType, boolean isStatement) {
|
||||||
WhenChecker.checkDeprecatedWhenSyntax(contextWithExpectedType.trace, expression);
|
WhenChecker.checkDeprecatedWhenSyntax(contextWithExpectedType.trace, expression);
|
||||||
|
WhenChecker.checkReservedPrefix(contextWithExpectedType.trace, expression);
|
||||||
|
|
||||||
components.dataFlowAnalyzer.recordExpectedType(contextWithExpectedType.trace, expression, contextWithExpectedType.expectedType);
|
components.dataFlowAnalyzer.recordExpectedType(contextWithExpectedType.trace, expression, contextWithExpectedType.expectedType);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
|
infix fun Any.sealed(a: Any?) {}
|
||||||
|
|
||||||
|
val x = 1 <!UNSUPPORTED!>sealed<!> when (1) {
|
||||||
|
1 -> 1
|
||||||
|
else -> 2
|
||||||
|
}
|
||||||
|
|
||||||
|
val x1 = 1 <!UNSUPPORTED!>sealed<!> /**/ when (1) {
|
||||||
|
1 -> 1
|
||||||
|
else -> 2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo() {
|
||||||
|
<!UNRESOLVED_REFERENCE, UNSUPPORTED!>sealed<!><!SYNTAX!><!> when {
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
1 <!UNSUPPORTED!>sealed<!> when {
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
1 sealed (when {
|
||||||
|
else -> {}
|
||||||
|
})
|
||||||
|
|
||||||
|
<!UNUSED_EXPRESSION!>1<!>
|
||||||
|
<!UNRESOLVED_REFERENCE, UNSUPPORTED!>sealed<!><!SYNTAX!><!> when {
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
|
||||||
|
1 <!UNSUPPORTED!>sealed<!>
|
||||||
|
when {
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -18186,6 +18186,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("When.kt")
|
||||||
public void testWhen() throws Exception {
|
public void testWhen() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/When.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/when/When.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user