Report 'nested class accessed via instance reference' error
This commit is contained in:
@@ -591,6 +591,7 @@ public interface Errors {
|
||||
DiagnosticFactory1<JetSimpleNameExpression, ClassifierDescriptor> NO_CLASS_OBJECT = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<JetSimpleNameExpression, TypeParameterDescriptor> TYPE_PARAMETER_IS_NOT_AN_EXPRESSION = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<JetSimpleNameExpression, TypeParameterDescriptor> TYPE_PARAMETER_ON_LHS_OF_DOT = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<JetExpression, ClassDescriptor> NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, ClassDescriptor> INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> NESTED_CLASS_NOT_ALLOWED = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
+1
@@ -259,6 +259,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION, "Type parameter ''{0}'' is not an expression", NAME);
|
||||
MAP.put(TYPE_PARAMETER_ON_LHS_OF_DOT, "Type parameter ''{0}'' cannot have or inherit a class object, so it cannot be on the left hand side of dot", NAME);
|
||||
MAP.put(NO_GENERICS_IN_SUPERTYPE_SPECIFIER, "Generic arguments of the base type must be specified");
|
||||
MAP.put(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE, "Nested {0} accessed via instance reference", RENDER_CLASS_OR_OBJECT_NAME);
|
||||
|
||||
MAP.put(INACCESSIBLE_OUTER_CLASS_EXPRESSION, "Expression is inaccessible from a nested class ''{0}'', use ''inner'' keyword to make the class inner", NAME);
|
||||
MAP.put(NESTED_CLASS_NOT_ALLOWED, "Nested class is not allowed here, use ''inner'' keyword to make the class inner");
|
||||
|
||||
+24
@@ -17,5 +17,29 @@
|
||||
package org.jetbrains.jet.lang.diagnostics.rendering
|
||||
|
||||
import org.jetbrains.jet.renderer.Renderer
|
||||
import org.jetbrains.jet.lang.descriptors.ClassKind
|
||||
import org.jetbrains.jet.lang.descriptors.ClassKind.*
|
||||
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
|
||||
import org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject
|
||||
|
||||
public fun <P> renderParameter(parameter: P, renderer: Renderer<P>?): Any = renderer?.render(parameter) ?: parameter
|
||||
|
||||
public fun ClassDescriptor.renderKindWithName(): String {
|
||||
val kind = getKind().getText()
|
||||
if (isClassObject(this)) {
|
||||
return "$kind of '${getContainingDeclaration().getName()}'"
|
||||
}
|
||||
return "$kind '${getName()}'"
|
||||
}
|
||||
|
||||
public fun ClassKind.getText(): String {
|
||||
return when (this) {
|
||||
CLASS -> "class"
|
||||
TRAIT -> "trait"
|
||||
ENUM_CLASS -> "enum class"
|
||||
ENUM_ENTRY -> "enum entry"
|
||||
ANNOTATION_CLASS -> "annotation class"
|
||||
OBJECT -> "object"
|
||||
CLASS_OBJECT -> "class object"
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,14 @@ public class Renderers {
|
||||
return "Class" + name;
|
||||
}
|
||||
return "Object" + name;
|
||||
}
|
||||
};
|
||||
|
||||
public static final Renderer<ClassDescriptor> RENDER_CLASS_OR_OBJECT_NAME = new Renderer<ClassDescriptor>() {
|
||||
@NotNull
|
||||
@Override
|
||||
public String render(@NotNull ClassDescriptor classifier) {
|
||||
return RenderingPackage.renderKindWithName(classifier);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+21
@@ -298,6 +298,7 @@ public class CallExpressionResolver {
|
||||
JetType selectorReturnType = selectorReturnTypeInfo.getType();
|
||||
|
||||
resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, expression, context);
|
||||
checkNestedClassAccess(expression, context);
|
||||
|
||||
//TODO move further
|
||||
if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
|
||||
@@ -338,4 +339,24 @@ public class CallExpressionResolver {
|
||||
? context.trace.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) calleeExpression) : null;
|
||||
ReceiversPackage.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor);
|
||||
}
|
||||
|
||||
private static void checkNestedClassAccess(
|
||||
@NotNull JetQualifiedExpression expression,
|
||||
@NotNull ExpressionTypingContext context
|
||||
) {
|
||||
JetExpression selectorExpression = expression.getSelectorExpression();
|
||||
if (selectorExpression == null) return;
|
||||
|
||||
// A.B - if B is a nested class accessed by outer class, 'A' and 'A.B' were marked as qualifiers
|
||||
// a.B - if B is a nested class accessed by instance reference, 'a.B' was marked as a qualifier, but 'a' was not (it's an expression)
|
||||
|
||||
QualifierReceiver expressionQualifier = context.trace.get(BindingContext.QUALIFIER_RECEIVER, expression);
|
||||
QualifierReceiver receiverQualifier = context.trace.get(BindingContext.QUALIFIER_RECEIVER, expression.getReceiverExpression());
|
||||
|
||||
if (receiverQualifier == null && expressionQualifier != null) {
|
||||
assert expressionQualifier.getClassifier() instanceof ClassDescriptor :
|
||||
"Only class can (package cannot) be accessed by instance reference: " + expressionQualifier;
|
||||
context.trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on(selectorExpression, (ClassDescriptor)expressionQualifier.getClassifier()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.jetbrains.jet.lang.resolve.calls.model.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.ResolutionStatus;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
|
||||
import org.jetbrains.jet.lang.resolve.calls.tasks.TaskPrioritizer;
|
||||
import org.jetbrains.jet.lang.resolve.calls.util.FakeCallableDescriptorForObject;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.jet.lang.types.*;
|
||||
@@ -115,6 +116,9 @@ public class CandidateResolver {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!checkThisObject(context)) {
|
||||
candidateCall.addStatus(OTHER_ERROR);
|
||||
}
|
||||
|
||||
List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments();
|
||||
if (jetTypeArguments.isEmpty()) {
|
||||
@@ -167,6 +171,31 @@ public class CandidateResolver {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkThisObject(@NotNull CallCandidateResolutionContext<?> context) {
|
||||
MutableResolvedCall<? extends CallableDescriptor> candidateCall = context.candidateCall;
|
||||
CallableDescriptor candidateDescriptor = candidateCall.getCandidateDescriptor();
|
||||
ReceiverValue thisObject = candidateCall.getThisObject();
|
||||
if (thisObject.exists()) {
|
||||
ClassDescriptor nestedClass = null;
|
||||
if (candidateDescriptor instanceof ConstructorDescriptor
|
||||
&& DescriptorUtils.isStaticNestedClass(candidateDescriptor.getContainingDeclaration())) {
|
||||
nestedClass = (ClassDescriptor) candidateDescriptor.getContainingDeclaration();
|
||||
}
|
||||
else if (candidateDescriptor instanceof FakeCallableDescriptorForObject) {
|
||||
nestedClass = ((FakeCallableDescriptorForObject) candidateDescriptor).getReferencedDescriptor();
|
||||
}
|
||||
if (nestedClass != null) {
|
||||
context.tracing.nestedClassAccessViaInstanceReference(context.trace, nestedClass);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
assert (thisObject.exists() == (candidateCall.getResultingDescriptor().getExpectedThisObject() != null))
|
||||
: "Shouldn't happen because of TaskPrioritizer: " + candidateDescriptor;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean checkOuterClassMemberIsAccessible(@NotNull CallCandidateResolutionContext<?> context) {
|
||||
// In "this@Outer.foo()" the error will be reported on "this@Outer" instead
|
||||
if (context.call.getExplicitReceiver().exists() || context.call.getThisObject().exists()) return true;
|
||||
|
||||
-3
@@ -207,9 +207,6 @@ import static org.jetbrains.jet.lang.resolve.calls.ValueArgumentsToParametersMap
|
||||
processFunctionLiteralArguments();
|
||||
reportUnmappedParameters();
|
||||
checkReceiverArgument();
|
||||
|
||||
assert (candidateCall.getThisObject().exists() == (candidateCall.getResultingDescriptor().getExpectedThisObject() != null))
|
||||
: "Shouldn't happen because of TaskPrioritizer: " + candidateCall.getCandidateDescriptor();
|
||||
}
|
||||
|
||||
private void processFunctionLiteralArguments() {
|
||||
|
||||
+6
-4
@@ -20,10 +20,7 @@ import com.google.common.collect.Sets;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorWithVisibility;
|
||||
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.inference.*;
|
||||
@@ -130,6 +127,11 @@ public abstract class AbstractTracingStrategy implements TracingStrategy {
|
||||
trace.report(CREATING_AN_INSTANCE_OF_ABSTRACT_CLASS.on(call.getCallElement()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nestedClassAccessViaInstanceReference(@NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor) {
|
||||
trace.report(NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE.on(reference, classDescriptor));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke) {
|
||||
ASTNode callOperationNode = call.getCallOperationNode();
|
||||
|
||||
@@ -275,12 +275,6 @@ public class TaskPrioritizer {
|
||||
@NotNull Call call
|
||||
) {
|
||||
for (D descriptor : descriptors) {
|
||||
if (descriptor instanceof ConstructorDescriptor && DescriptorUtils.isStaticNestedClass(descriptor.getContainingDeclaration())
|
||||
|| descriptor instanceof FakeCallableDescriptorForObject) {
|
||||
// We don't want static nested class constructor or class object / object (as callable)
|
||||
// to be resolved with expectedThisObject
|
||||
continue;
|
||||
}
|
||||
ResolutionCandidate<D> candidate = ResolutionCandidate.create(call, descriptor);
|
||||
candidate.setThisObject(thisObject);
|
||||
candidate.setReceiverArgument(receiverParameter);
|
||||
|
||||
+6
-4
@@ -17,10 +17,7 @@
|
||||
package org.jetbrains.jet.lang.resolve.calls.tasks;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptorWithVisibility;
|
||||
import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.*;
|
||||
import org.jetbrains.jet.lang.psi.Call;
|
||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
@@ -83,6 +80,9 @@ public interface TracingStrategy {
|
||||
@Override
|
||||
public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {}
|
||||
|
||||
@Override
|
||||
public void nestedClassAccessViaInstanceReference(@NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor) {}
|
||||
|
||||
@Override
|
||||
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke) {}
|
||||
|
||||
@@ -132,6 +132,8 @@ public interface TracingStrategy {
|
||||
|
||||
void instantiationOfAbstractClass(@NotNull BindingTrace trace);
|
||||
|
||||
void nestedClassAccessViaInstanceReference(@NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor);
|
||||
|
||||
void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke);
|
||||
|
||||
void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type);
|
||||
|
||||
+10
-10
@@ -591,16 +591,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
return null;
|
||||
}
|
||||
|
||||
ReceiverValue receiver = new TransientReceiver(lhsType);
|
||||
TemporaryTraceAndCache temporaryWithReceiver = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve callable reference with receiver", reference);
|
||||
CallableDescriptor descriptor = resolveCallableNotCheckingArguments(
|
||||
reference, receiver, context.replaceTraceAndCache(temporaryWithReceiver), result);
|
||||
if (result[0]) {
|
||||
temporaryWithReceiver.commit();
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
JetScope staticScope = getStaticNestedClassesScope((ClassDescriptor) classifier);
|
||||
TemporaryTraceAndCache temporaryForStatic = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve callable reference in static scope", reference);
|
||||
@@ -611,6 +601,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
return possibleStaticNestedClassConstructor;
|
||||
}
|
||||
|
||||
ReceiverValue receiver = new TransientReceiver(lhsType);
|
||||
TemporaryTraceAndCache temporaryWithReceiver = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve callable reference with receiver", reference);
|
||||
CallableDescriptor descriptor = resolveCallableNotCheckingArguments(
|
||||
reference, receiver, context.replaceTraceAndCache(temporaryWithReceiver), result);
|
||||
if (result[0]) {
|
||||
temporaryWithReceiver.commit();
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -454,6 +454,13 @@ public class ControlStructureTypingUtils {
|
||||
throwError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nestedClassAccessViaInstanceReference(
|
||||
@NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor
|
||||
) {
|
||||
throwError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unsafeCall(
|
||||
@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke
|
||||
|
||||
@@ -13,6 +13,6 @@ class C {
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val res = C().Obj.o + C().Obj.InnerObj.k() + C().Obj.D().ko
|
||||
val res = C.Obj.o + C.Obj.InnerObj.k() + C.Obj.D().ko
|
||||
return if (res == "OKKO") "OK" else "Fail: $res"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fun main(args: Array<String>) {
|
||||
val str = aaa.A().E.A
|
||||
val str = aaa.A.E.A
|
||||
if (str.toString() != "A") {
|
||||
throw Exception()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fun main(args: Array<String>) {
|
||||
val str = aaa.A().O.s
|
||||
val str = aaa.A.O.s
|
||||
if (str != "OK") {
|
||||
throw Exception()
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@ class Outer {
|
||||
|
||||
fun Outer.foo() {
|
||||
Outer()
|
||||
<!UNRESOLVED_REFERENCE!>Nested<!>()
|
||||
<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>Nested<!>()
|
||||
Inner()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
trait N { fun foo() = 1 }
|
||||
|
||||
class WithClassObject {
|
||||
class object {}
|
||||
|
||||
class Nested()
|
||||
class NestedWithClassObject { class object : N }
|
||||
enum class NestedEnum { A }
|
||||
object NestedObj : N { fun invoke() = 1 }
|
||||
}
|
||||
|
||||
class WithoutClassObject {
|
||||
class Nested()
|
||||
class NestedWithClassObject { class object : N }
|
||||
enum class NestedEnum { A }
|
||||
object NestedObj : N { fun invoke() = 1 }
|
||||
}
|
||||
|
||||
object Obj {
|
||||
class Nested()
|
||||
class NestedWithClassObject { class object : N }
|
||||
enum class NestedEnum { A }
|
||||
object NestedObj : N { fun invoke() = 1 }
|
||||
}
|
||||
|
||||
fun test(with: WithClassObject, without: WithoutClassObject, obj: Obj) {
|
||||
with.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>Nested<!>()
|
||||
with.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedWithClassObject<!>
|
||||
with.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedWithClassObject<!>()
|
||||
with.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedWithClassObject<!>.foo()
|
||||
with.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedEnum<!>.A
|
||||
with.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedObj<!>
|
||||
with.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedObj<!>()
|
||||
with.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedObj<!>.foo()
|
||||
|
||||
without.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>Nested<!>()
|
||||
without.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedWithClassObject<!>
|
||||
without.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedWithClassObject<!>()
|
||||
without.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedWithClassObject<!>.foo()
|
||||
without.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedEnum<!>.A
|
||||
without.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedObj<!>
|
||||
without.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedObj<!>()
|
||||
without.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedObj<!>.foo()
|
||||
|
||||
obj.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>Nested<!>()
|
||||
obj.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedWithClassObject<!>
|
||||
obj.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedWithClassObject<!>()
|
||||
obj.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedWithClassObject<!>.foo()
|
||||
obj.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedEnum<!>.A
|
||||
obj.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedObj<!>
|
||||
obj.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedObj<!>()
|
||||
obj.<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>NestedObj<!>.foo()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
//no nested class access via instance reference error
|
||||
fun test() {
|
||||
A.f(<!TYPE_MISMATCH!>""<!>)
|
||||
}
|
||||
|
||||
class A() {
|
||||
class object {
|
||||
object f {
|
||||
fun invoke(i: Int) = i
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -6,7 +6,7 @@ class A {
|
||||
}
|
||||
|
||||
fun A.main() {
|
||||
::<!UNRESOLVED_REFERENCE!>Nested<!>
|
||||
::<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>Nested<!>
|
||||
val y = A::Nested
|
||||
|
||||
y : KFunction0<A.Nested>
|
||||
|
||||
@@ -4944,6 +4944,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
doTest("compiler/testData/diagnostics/tests/inner/modality.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedClassAccessedViaInstanceReference.kt")
|
||||
public void testNestedClassAccessedViaInstanceReference() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inner/nestedClassAccessedViaInstanceReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedClassExtendsOuter.kt")
|
||||
public void testNestedClassExtendsOuter() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/inner/nestedClassExtendsOuter.kt");
|
||||
@@ -5896,6 +5901,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/objects"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("invokeOnInnerObject.kt")
|
||||
public void testInvokeOnInnerObject() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/objects/invokeOnInnerObject.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("kt2240.kt")
|
||||
public void testKt2240() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/objects/kt2240.kt");
|
||||
|
||||
@@ -6,5 +6,5 @@ object A {
|
||||
|
||||
fun test<T>(a: T) {
|
||||
val c = (a as A)
|
||||
c.<error descr="[FUNCTION_EXPECTED] Expression 'B' of type '[Package-type B]' cannot be invoked as a function. The function invoke() is not found"><error>B</error></error>()
|
||||
c.<error descr="[NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE] Nested class 'B' accessed via instance reference">B</error>()
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// !DIAGNOSTICS_NUMBER: 4
|
||||
// !DIAGNOSTICS: NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE
|
||||
|
||||
class A {
|
||||
class Nested()
|
||||
class NestedWithClassObject { class object }
|
||||
enum class NestedEnum { A }
|
||||
object NestedObj { fun invoke() = 1 }
|
||||
}
|
||||
|
||||
fun test(a: A) {
|
||||
a.Nested()
|
||||
a.NestedWithClassObject
|
||||
a.NestedEnum
|
||||
a.NestedObj
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<!-- nestedClassAcessedViaInstanceReference1 -->
|
||||
Nested class 'Nested' accessed via instance reference
|
||||
@@ -0,0 +1,2 @@
|
||||
<!-- nestedClassAcessedViaInstanceReference2 -->
|
||||
Nested class object of 'NestedWithClassObject' accessed via instance reference
|
||||
@@ -0,0 +1,2 @@
|
||||
<!-- nestedClassAcessedViaInstanceReference3 -->
|
||||
Nested enum class 'NestedEnum' accessed via instance reference
|
||||
@@ -0,0 +1,2 @@
|
||||
<!-- nestedClassAcessedViaInstanceReference4 -->
|
||||
Nested object 'NestedObj' accessed via instance reference
|
||||
@@ -98,6 +98,11 @@ public class DiagnosticMessageTestGenerated extends AbstractDiagnosticMessageTes
|
||||
doTest("idea/testData/diagnosticMessage/nameInConstraintIsNotATypeParameter.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("nestedClassAcessedViaInstanceReference.kt")
|
||||
public void testNestedClassAcessedViaInstanceReference() throws Exception {
|
||||
doTest("idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("noneApplicable.kt")
|
||||
public void testNoneApplicable() throws Exception {
|
||||
doTest("idea/testData/diagnosticMessage/noneApplicable.kt");
|
||||
|
||||
@@ -5,32 +5,25 @@ enum class A {
|
||||
|
||||
BAR : A() {
|
||||
fun explicitFromEntry() = A.FOO
|
||||
//fun byThisFromEntry() = this.FOO
|
||||
fun implicitFromEntry() = FOO
|
||||
}
|
||||
|
||||
fun explicit() = A.FOO
|
||||
fun byThis() = this.FOO
|
||||
fun implicit() = FOO
|
||||
}
|
||||
|
||||
fun A.extExplicit() = A.FOO
|
||||
fun A.extByThis() = this.FOO
|
||||
//fun A.extImplicit() = FOO
|
||||
|
||||
fun box(): String {
|
||||
assertEquals(A.FOO, A.FOO.explicit(), "explicit access")
|
||||
assertEquals(A.FOO, A.FOO.byThis(), "access by this")
|
||||
assertEquals(A.FOO, A.FOO.implicit(), "implicit access")
|
||||
|
||||
assertEquals(A.FOO, A.FOO.explicit(), "explicit access from BAR")
|
||||
// TODO uncoment when KT-4692 will be fixed
|
||||
//assertEquals(A.FOO, A.FOO.byThis(), "access by this from BAR")
|
||||
assertEquals(A.FOO, A.FOO.implicit(), "implicit access from BAR")
|
||||
|
||||
assertEquals(A.FOO, A.FOO.extExplicit(), "explicit access from ext fun")
|
||||
assertEquals(A.FOO, A.FOO.extByThis(), "access by this from ext fun")
|
||||
// TODO uncoment when KT-4692 will be fixed
|
||||
// TODO uncoment when KT-5605 will be fixed
|
||||
//assertEquals(A.FOO, A.FOO.extImplicit(), "implicit access from ext fun")
|
||||
|
||||
return "OK"
|
||||
|
||||
Reference in New Issue
Block a user