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, ClassifierDescriptor> NO_CLASS_OBJECT = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory1<JetSimpleNameExpression, TypeParameterDescriptor> TYPE_PARAMETER_IS_NOT_AN_EXPRESSION = 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<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);
|
DiagnosticFactory1<PsiElement, ClassDescriptor> INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR);
|
||||||
DiagnosticFactory0<PsiElement> NESTED_CLASS_NOT_ALLOWED = DiagnosticFactory0.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_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(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(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(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");
|
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
|
package org.jetbrains.jet.lang.diagnostics.rendering
|
||||||
|
|
||||||
import org.jetbrains.jet.renderer.Renderer
|
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 <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 "Class" + name;
|
||||||
}
|
}
|
||||||
return "Object" + 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();
|
JetType selectorReturnType = selectorReturnTypeInfo.getType();
|
||||||
|
|
||||||
resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, expression, context);
|
resolveDeferredReceiverInQualifiedExpression(qualifierReceiver, expression, context);
|
||||||
|
checkNestedClassAccess(expression, context);
|
||||||
|
|
||||||
//TODO move further
|
//TODO move further
|
||||||
if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
|
if (expression.getOperationSign() == JetTokens.SAFE_ACCESS) {
|
||||||
@@ -338,4 +339,24 @@ public class CallExpressionResolver {
|
|||||||
? context.trace.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) calleeExpression) : null;
|
? context.trace.get(BindingContext.REFERENCE_TARGET, (JetReferenceExpression) calleeExpression) : null;
|
||||||
ReceiversPackage.resolveAsReceiverInQualifiedExpression(qualifierReceiver, context, selectorDescriptor);
|
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.results.ResolutionStatus;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.tasks.ResolutionTask;
|
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.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.ExpressionReceiver;
|
||||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||||
import org.jetbrains.jet.lang.types.*;
|
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();
|
List<JetTypeProjection> jetTypeArguments = context.call.getTypeArguments();
|
||||||
if (jetTypeArguments.isEmpty()) {
|
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) {
|
private static boolean checkOuterClassMemberIsAccessible(@NotNull CallCandidateResolutionContext<?> context) {
|
||||||
// In "this@Outer.foo()" the error will be reported on "this@Outer" instead
|
// In "this@Outer.foo()" the error will be reported on "this@Outer" instead
|
||||||
if (context.call.getExplicitReceiver().exists() || context.call.getThisObject().exists()) return true;
|
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();
|
processFunctionLiteralArguments();
|
||||||
reportUnmappedParameters();
|
reportUnmappedParameters();
|
||||||
checkReceiverArgument();
|
checkReceiverArgument();
|
||||||
|
|
||||||
assert (candidateCall.getThisObject().exists() == (candidateCall.getResultingDescriptor().getExpectedThisObject() != null))
|
|
||||||
: "Shouldn't happen because of TaskPrioritizer: " + candidateCall.getCandidateDescriptor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processFunctionLiteralArguments() {
|
private void processFunctionLiteralArguments() {
|
||||||
|
|||||||
+6
-4
@@ -20,10 +20,7 @@ import com.google.common.collect.Sets;
|
|||||||
import com.intellij.lang.ASTNode;
|
import com.intellij.lang.ASTNode;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
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.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
import org.jetbrains.jet.lang.resolve.calls.inference.*;
|
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()));
|
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
|
@Override
|
||||||
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke) {
|
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke) {
|
||||||
ASTNode callOperationNode = call.getCallOperationNode();
|
ASTNode callOperationNode = call.getCallOperationNode();
|
||||||
|
|||||||
@@ -275,12 +275,6 @@ public class TaskPrioritizer {
|
|||||||
@NotNull Call call
|
@NotNull Call call
|
||||||
) {
|
) {
|
||||||
for (D descriptor : descriptors) {
|
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);
|
ResolutionCandidate<D> candidate = ResolutionCandidate.create(call, descriptor);
|
||||||
candidate.setThisObject(thisObject);
|
candidate.setThisObject(thisObject);
|
||||||
candidate.setReceiverArgument(receiverParameter);
|
candidate.setReceiverArgument(receiverParameter);
|
||||||
|
|||||||
+6
-4
@@ -17,10 +17,7 @@
|
|||||||
package org.jetbrains.jet.lang.resolve.calls.tasks;
|
package org.jetbrains.jet.lang.resolve.calls.tasks;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
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.psi.Call;
|
import org.jetbrains.jet.lang.psi.Call;
|
||||||
import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument;
|
import org.jetbrains.jet.lang.psi.JetFunctionLiteralArgument;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||||
@@ -83,6 +80,9 @@ public interface TracingStrategy {
|
|||||||
@Override
|
@Override
|
||||||
public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {}
|
public void instantiationOfAbstractClass(@NotNull BindingTrace trace) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nestedClassAccessViaInstanceReference(@NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke) {}
|
public void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke) {}
|
||||||
|
|
||||||
@@ -132,6 +132,8 @@ public interface TracingStrategy {
|
|||||||
|
|
||||||
void instantiationOfAbstractClass(@NotNull BindingTrace trace);
|
void instantiationOfAbstractClass(@NotNull BindingTrace trace);
|
||||||
|
|
||||||
|
void nestedClassAccessViaInstanceReference(@NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor);
|
||||||
|
|
||||||
void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke);
|
void unsafeCall(@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke);
|
||||||
|
|
||||||
void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type);
|
void unnecessarySafeCall(@NotNull BindingTrace trace, @NotNull JetType type);
|
||||||
|
|||||||
+10
-10
@@ -591,16 +591,6 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return null;
|
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);
|
JetScope staticScope = getStaticNestedClassesScope((ClassDescriptor) classifier);
|
||||||
TemporaryTraceAndCache temporaryForStatic = TemporaryTraceAndCache.create(
|
TemporaryTraceAndCache temporaryForStatic = TemporaryTraceAndCache.create(
|
||||||
context, "trace to resolve callable reference in static scope", reference);
|
context, "trace to resolve callable reference in static scope", reference);
|
||||||
@@ -611,6 +601,16 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
|||||||
return possibleStaticNestedClassConstructor;
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
@@ -454,6 +454,13 @@ public class ControlStructureTypingUtils {
|
|||||||
throwError();
|
throwError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nestedClassAccessViaInstanceReference(
|
||||||
|
@NotNull BindingTrace trace, @NotNull ClassDescriptor classDescriptor
|
||||||
|
) {
|
||||||
|
throwError();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void unsafeCall(
|
public void unsafeCall(
|
||||||
@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke
|
@NotNull BindingTrace trace, @NotNull JetType type, boolean isCallForImplicitInvoke
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ class C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun box(): String {
|
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"
|
return if (res == "OKKO") "OK" else "Fail: $res"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val str = aaa.A().E.A
|
val str = aaa.A.E.A
|
||||||
if (str.toString() != "A") {
|
if (str.toString() != "A") {
|
||||||
throw Exception()
|
throw Exception()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
val str = aaa.A().O.s
|
val str = aaa.A.O.s
|
||||||
if (str != "OK") {
|
if (str != "OK") {
|
||||||
throw Exception()
|
throw Exception()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ class Outer {
|
|||||||
|
|
||||||
fun Outer.foo() {
|
fun Outer.foo() {
|
||||||
Outer()
|
Outer()
|
||||||
<!UNRESOLVED_REFERENCE!>Nested<!>()
|
<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>Nested<!>()
|
||||||
Inner()
|
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() {
|
fun A.main() {
|
||||||
::<!UNRESOLVED_REFERENCE!>Nested<!>
|
::<!NESTED_CLASS_ACCESSED_VIA_INSTANCE_REFERENCE!>Nested<!>
|
||||||
val y = A::Nested
|
val y = A::Nested
|
||||||
|
|
||||||
y : KFunction0<A.Nested>
|
y : KFunction0<A.Nested>
|
||||||
|
|||||||
@@ -4944,6 +4944,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest("compiler/testData/diagnostics/tests/inner/modality.kt");
|
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")
|
@TestMetadata("nestedClassExtendsOuter.kt")
|
||||||
public void testNestedClassExtendsOuter() throws Exception {
|
public void testNestedClassExtendsOuter() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/inner/nestedClassExtendsOuter.kt");
|
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);
|
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")
|
@TestMetadata("kt2240.kt")
|
||||||
public void testKt2240() throws Exception {
|
public void testKt2240() throws Exception {
|
||||||
doTest("compiler/testData/diagnostics/tests/objects/kt2240.kt");
|
doTest("compiler/testData/diagnostics/tests/objects/kt2240.kt");
|
||||||
|
|||||||
@@ -6,5 +6,5 @@ object A {
|
|||||||
|
|
||||||
fun test<T>(a: T) {
|
fun test<T>(a: T) {
|
||||||
val c = (a as A)
|
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");
|
doTest("idea/testData/diagnosticMessage/nameInConstraintIsNotATypeParameter.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("nestedClassAcessedViaInstanceReference.kt")
|
||||||
|
public void testNestedClassAcessedViaInstanceReference() throws Exception {
|
||||||
|
doTest("idea/testData/diagnosticMessage/nestedClassAcessedViaInstanceReference.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("noneApplicable.kt")
|
@TestMetadata("noneApplicable.kt")
|
||||||
public void testNoneApplicable() throws Exception {
|
public void testNoneApplicable() throws Exception {
|
||||||
doTest("idea/testData/diagnosticMessage/noneApplicable.kt");
|
doTest("idea/testData/diagnosticMessage/noneApplicable.kt");
|
||||||
|
|||||||
@@ -5,32 +5,25 @@ enum class A {
|
|||||||
|
|
||||||
BAR : A() {
|
BAR : A() {
|
||||||
fun explicitFromEntry() = A.FOO
|
fun explicitFromEntry() = A.FOO
|
||||||
//fun byThisFromEntry() = this.FOO
|
|
||||||
fun implicitFromEntry() = FOO
|
fun implicitFromEntry() = FOO
|
||||||
}
|
}
|
||||||
|
|
||||||
fun explicit() = A.FOO
|
fun explicit() = A.FOO
|
||||||
fun byThis() = this.FOO
|
|
||||||
fun implicit() = FOO
|
fun implicit() = FOO
|
||||||
}
|
}
|
||||||
|
|
||||||
fun A.extExplicit() = A.FOO
|
fun A.extExplicit() = A.FOO
|
||||||
fun A.extByThis() = this.FOO
|
|
||||||
//fun A.extImplicit() = FOO
|
//fun A.extImplicit() = FOO
|
||||||
|
|
||||||
fun box(): String {
|
fun box(): String {
|
||||||
assertEquals(A.FOO, A.FOO.explicit(), "explicit access")
|
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.implicit(), "implicit access")
|
||||||
|
|
||||||
assertEquals(A.FOO, A.FOO.explicit(), "explicit access from BAR")
|
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.implicit(), "implicit access from BAR")
|
||||||
|
|
||||||
assertEquals(A.FOO, A.FOO.extExplicit(), "explicit access from ext fun")
|
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-5605 will be fixed
|
||||||
// TODO uncoment when KT-4692 will be fixed
|
|
||||||
//assertEquals(A.FOO, A.FOO.extImplicit(), "implicit access from ext fun")
|
//assertEquals(A.FOO, A.FOO.extImplicit(), "implicit access from ext fun")
|
||||||
|
|
||||||
return "OK"
|
return "OK"
|
||||||
|
|||||||
Reference in New Issue
Block a user