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:
Pavel V. Talanov
2015-12-28 16:49:46 +03:00
parent 06e829936e
commit 1c4d4f3e36
18 changed files with 127 additions and 9 deletions
@@ -81,7 +81,7 @@ public class OverloadResolver {
else if (containingDeclaration instanceof ScriptDescriptor) {
// 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);
}
}
@@ -321,6 +321,7 @@ public class CallExpressionResolver {
return getSimpleNameExpressionTypeInfo((KtSimpleNameExpression) selectorExpression, receiver, callOperationNode, context);
}
else if (selectorExpression != null) {
expressionTypingServices.getTypeInfo(selectorExpression, context);
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression, selectorExpression.getText()));
}
return TypeInfoFactoryKt.noTypeInfo(context);
@@ -1448,6 +1448,26 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
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
public KotlinTypeInfo getTypeInfoForBinaryCall(
@NotNull Name name,
@@ -1486,8 +1506,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
@Override
public KotlinTypeInfo visitDeclaration(@NotNull KtDeclaration dcl, ExpressionTypingContext context) {
context.trace.report(DECLARATION_IN_ILLEGAL_CONTEXT.on(dcl));
return TypeInfoFactoryKt.noTypeInfo(context);
return declarationInIllegalContext(dcl, context);
}
@Override
@@ -384,6 +384,11 @@ public abstract class ExpressionTypingVisitorDispatcher extends KtVisitor<Kotlin
return basic.visitDeclaration(dcl, data);
}
@Override
public KotlinTypeInfo visitClass(@NotNull KtClass klass, ExpressionTypingContext data) {
return basic.visitClass(klass, data);
}
@Override
public KotlinTypeInfo visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, ExpressionTypingContext data) {
return basic.visitStringTemplateExpression(expression, data);
@@ -1,8 +1,8 @@
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 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 returnTypeWithParameter = { (<!UNRESOLVED_REFERENCE!>b<!><!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
@@ -1,4 +1,4 @@
fun foo(s: String) {
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>
}
@@ -1,10 +1,10 @@
interface Hi {
fun foo(): Int
interface <lineMarker></lineMarker>Hi {
fun <lineMarker></lineMarker>foo(): Int
}
// Closing brace is intentionally missed
val id = array("kotlin.FlexibleType"
private class Some(): Hi {
override fun foo() = 1
override fun <lineMarker></lineMarker>foo() = 1
}
@@ -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>
<description>Property 'id' is never used</description>
</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>
@@ -394,6 +394,36 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
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")
public void testCoercionToUnit() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/CoercionToUnit.kt");
@@ -418,6 +448,12 @@ public class PsiCheckerTestGenerated extends AbstractPsiCheckerTest {
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")
public void testJavaStyleClassLiteralInAnnotationArguments() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/checker/regression/javaStyleClassLiteralInAnnotationArguments.kt");
@@ -157,6 +157,12 @@ public class HierarchyTestGenerated extends AbstractHierarchyTest {
doTypeClassHierarchyTest(fileName);
}
@TestMetadata("JavaStyleClassLiteralInvalidCode")
public void testJavaStyleClassLiteralInvalidCode() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/class/type/JavaStyleClassLiteralInvalidCode/");
doTypeClassHierarchyTest(fileName);
}
@TestMetadata("JetInt")
public void testJetInt() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/hierarchy/class/type/JetInt/");