Create class descriptors for local classes in illegal positions
Typecheck code in illegal selector position Fixes exceptions on "val p = A.class" erroneous code
This commit is contained in:
@@ -81,7 +81,7 @@ public class OverloadResolver {
|
|||||||
else if (containingDeclaration instanceof ScriptDescriptor) {
|
else if (containingDeclaration instanceof ScriptDescriptor) {
|
||||||
// TODO: check overload conflicts of functions with constructors in scripts
|
// TODO: check overload conflicts of functions with constructors in scripts
|
||||||
}
|
}
|
||||||
else if (!(containingDeclaration instanceof FunctionDescriptor)) {
|
else if (!(containingDeclaration instanceof FunctionDescriptor || containingDeclaration instanceof PropertyDescriptor)) {
|
||||||
throw new IllegalStateException("Illegal class container: " + containingDeclaration);
|
throw new IllegalStateException("Illegal class container: " + containingDeclaration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,6 +321,7 @@ public class CallExpressionResolver {
|
|||||||
return getSimpleNameExpressionTypeInfo((KtSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
|
return getSimpleNameExpressionTypeInfo((KtSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
|
||||||
}
|
}
|
||||||
else if (selectorExpression != null) {
|
else if (selectorExpression != null) {
|
||||||
|
expressionTypingServices.getTypeInfo(selectorExpression, context);
|
||||||
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
|
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
|
||||||
}
|
}
|
||||||
return TypeInfoFactoryKt.noTypeInfo(context);
|
return TypeInfoFactoryKt.noTypeInfo(context);
|
||||||
|
|||||||
+21
-2
@@ -1448,6 +1448,26 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return components.dataFlowAnalyzer.checkType(resolveArrayAccessGetMethod(expression, context), expression, context);
|
return components.dataFlowAnalyzer.checkType(resolveArrayAccessGetMethod(expression, context), expression, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KotlinTypeInfo visitClass(@NotNull KtClass klass, ExpressionTypingContext context) {
|
||||||
|
// analyze class in illegal position and write descriptor to trace but do not write to any scope
|
||||||
|
components.localClassifierAnalyzer.processClassOrObject(
|
||||||
|
null, context.replaceContextDependency(INDEPENDENT),
|
||||||
|
context.scope.getOwnerDescriptor(),
|
||||||
|
klass
|
||||||
|
);
|
||||||
|
return declarationInIllegalContext(klass, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static KotlinTypeInfo declarationInIllegalContext(
|
||||||
|
@NotNull KtDeclaration declaration,
|
||||||
|
@NotNull ExpressionTypingContext context
|
||||||
|
) {
|
||||||
|
context.trace.report(DECLARATION_IN_ILLEGAL_CONTEXT.on(declaration));
|
||||||
|
return TypeInfoFactoryKt.noTypeInfo(context);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public KotlinTypeInfo getTypeInfoForBinaryCall(
|
public KotlinTypeInfo getTypeInfoForBinaryCall(
|
||||||
@NotNull Name name,
|
@NotNull Name name,
|
||||||
@@ -1486,8 +1506,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KotlinTypeInfo visitDeclaration(@NotNull KtDeclaration dcl, ExpressionTypingContext context) {
|
public KotlinTypeInfo visitDeclaration(@NotNull KtDeclaration dcl, ExpressionTypingContext context) {
|
||||||
context.trace.report(DECLARATION_IN_ILLEGAL_CONTEXT.on(dcl));
|
return declarationInIllegalContext(dcl, context);
|
||||||
return TypeInfoFactoryKt.noTypeInfo(context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+5
@@ -384,6 +384,11 @@ public abstract class ExpressionTypingVisitorDispatcher extends KtVisitor<Kotlin
|
|||||||
return basic.visitDeclaration(dcl, data);
|
return basic.visitDeclaration(dcl, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public KotlinTypeInfo visitClass(@NotNull KtClass klass, ExpressionTypingContext data) {
|
||||||
|
return basic.visitClass(klass, data);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public KotlinTypeInfo visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, ExpressionTypingContext data) {
|
public KotlinTypeInfo visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, ExpressionTypingContext data) {
|
||||||
return basic.visitStringTemplateExpression(expression, data);
|
return basic.visitStringTemplateExpression(expression, data);
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
val receiver = { Int.(<!SYNTAX!><!>) <!SYNTAX!>-><!> }
|
val receiver = { Int.(<!SYNTAX!><!>) <!SYNTAX!>-><!> }
|
||||||
val receiverWithParameter = { Int.<!ILLEGAL_SELECTOR!>(<!DEBUG_INFO_MISSING_UNRESOLVED!>a<!>)<!> <!SYNTAX!>-><!> }
|
val receiverWithParameter = { Int.<!ILLEGAL_SELECTOR!>(<!UNRESOLVED_REFERENCE!>a<!>)<!> <!SYNTAX!>-><!> }
|
||||||
|
|
||||||
val receiverAndReturnType = { Int.(<!SYNTAX!><!>)<!SYNTAX!>: Int -> 5<!> }
|
val receiverAndReturnType = { Int.(<!SYNTAX!><!>)<!SYNTAX!>: Int -> 5<!> }
|
||||||
val receiverAndReturnTypeWithParameter = { Int.(<!DEBUG_INFO_MISSING_UNRESOLVED!>a<!><!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
|
val receiverAndReturnTypeWithParameter = { Int.(<!UNRESOLVED_REFERENCE!>a<!><!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
|
||||||
|
|
||||||
val returnType = { (<!SYNTAX!><!>)<!SYNTAX!>: Int -> 5<!> }
|
val returnType = { (<!SYNTAX!><!>)<!SYNTAX!>: Int -> 5<!> }
|
||||||
val returnTypeWithParameter = { (<!UNRESOLVED_REFERENCE!>b<!><!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
|
val returnTypeWithParameter = { (<!UNRESOLVED_REFERENCE!>b<!><!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
fun foo(s: String) {
|
fun foo(s: String) {
|
||||||
s.
|
s.
|
||||||
<!ILLEGAL_SELECTOR!>val b = 42<!>
|
<!DECLARATION_IN_ILLEGAL_CONTEXT, ILLEGAL_SELECTOR!>val b = 42<!>
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
class A
|
||||||
|
|
||||||
|
fun f() {
|
||||||
|
A.class<EOLError descr="Name expected"></EOLError>
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
class A
|
||||||
|
|
||||||
|
fun f() {
|
||||||
|
A.<error>class B {
|
||||||
|
fun f() {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}</error>
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
val p = 1 < <error>class A {
|
||||||
|
fun f() {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}</error>
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
fun g() = 1 < <error>class A</error>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun f(<warning>i</warning>: Int = 3 < <error>class A {
|
||||||
|
fun f() {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}</error>) {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
class A
|
||||||
|
|
||||||
|
fun f() {
|
||||||
|
A.<error>fun <error>g</error>() {
|
||||||
|
<error descr="[UNRESOLVED_REFERENCE] Unresolved reference: g">g</error>()
|
||||||
|
}</error>
|
||||||
|
}
|
||||||
+3
-3
@@ -1,10 +1,10 @@
|
|||||||
interface Hi {
|
interface <lineMarker></lineMarker>Hi {
|
||||||
fun foo(): Int
|
fun <lineMarker></lineMarker>foo(): Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Closing brace is intentionally missed
|
// Closing brace is intentionally missed
|
||||||
val id = array("kotlin.FlexibleType"
|
val id = array("kotlin.FlexibleType"
|
||||||
|
|
||||||
private class Some(): Hi {
|
private class Some(): Hi {
|
||||||
override fun foo() = 1
|
override fun <lineMarker></lineMarker>foo() = 1
|
||||||
}
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
<node text="Object (java.lang)">
|
||||||
|
<node text="no_name_in_PSI_3d19d79d_1ba9_4cd0_b7f5_b46aa3cd5d40 in f() in main.kt ()" base="true"/>
|
||||||
|
</node>
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class A
|
||||||
|
|
||||||
|
fun f() {
|
||||||
|
A.class<caret>
|
||||||
|
}
|
||||||
|
|
||||||
@@ -55,4 +55,12 @@
|
|||||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused Symbol</problem_class>
|
||||||
<description>Property 'id' is never used</description>
|
<description>Property 'id' is never used</description>
|
||||||
</problem>
|
</problem>
|
||||||
|
<problem>
|
||||||
|
<file>BadCodeNoExceptions.kt</file>
|
||||||
|
<line>4</line>
|
||||||
|
<module>light_idea_test_case</module>
|
||||||
|
<entry_point TYPE="file" FQNAME="temp:///src/BadCodeNoExceptions.kt" />
|
||||||
|
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused symbol</problem_class>
|
||||||
|
<description>Class 'Some' is never used</description>
|
||||||
|
</problem>
|
||||||
</problems>
|
</problems>
|
||||||
|
|||||||
@@ -394,6 +394,36 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassDeclarationAfterDot.kt")
|
||||||
|
public void testClassDeclarationAfterDot() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/ClassDeclarationAfterDot.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassDeclarationAfterDot2.kt")
|
||||||
|
public void testClassDeclarationAfterDot2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/ClassDeclarationAfterDot2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassDeclarationAsExpression.kt")
|
||||||
|
public void testClassDeclarationAsExpression() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/ClassDeclarationAsExpression.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassDeclarationAsExpression2.kt")
|
||||||
|
public void testClassDeclarationAsExpression2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/ClassDeclarationAsExpression2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("ClassDeclarationAsExpression3.kt")
|
||||||
|
public void testClassDeclarationAsExpression3() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/ClassDeclarationAsExpression3.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("CoercionToUnit.kt")
|
@TestMetadata("CoercionToUnit.kt")
|
||||||
public void testCoercionToUnit() throws Exception {
|
public void testCoercionToUnit() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/CoercionToUnit.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/CoercionToUnit.kt");
|
||||||
@@ -418,6 +448,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("FunDeclarationAfterDot.kt")
|
||||||
|
public void testFunDeclarationAfterDot() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/FunDeclarationAfterDot.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("javaStyleClassLiteralInAnnotationArguments.kt")
|
@TestMetadata("javaStyleClassLiteralInAnnotationArguments.kt")
|
||||||
public void testJavaStyleClassLiteralInAnnotationArguments() throws Exception {
|
public void testJavaStyleClassLiteralInAnnotationArguments() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/javaStyleClassLiteralInAnnotationArguments.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/javaStyleClassLiteralInAnnotationArguments.kt");
|
||||||
|
|||||||
@@ -157,6 +157,12 @@ public class HierarchyTestGenerated extends AbstractHierarchyTest {
|
|||||||
doTypeClassHierarchyTest(fileName);
|
doTypeClassHierarchyTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("JavaStyleClassLiteralInvalidCode")
|
||||||
|
public void testJavaStyleClassLiteralInvalidCode() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/class/type/JavaStyleClassLiteralInvalidCode/");
|
||||||
|
doTypeClassHierarchyTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("JetInt")
|
@TestMetadata("JetInt")
|
||||||
public void testJetInt() throws Exception {
|
public void testJetInt() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/class/type/JetInt/");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/class/type/JetInt/");
|
||||||
|
|||||||
Reference in New Issue
Block a user