diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/impl/MutableClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/impl/MutableClassDescriptor.java index 65cf9c13207..1a4c0997569 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/impl/MutableClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/descriptors/impl/MutableClassDescriptor.java @@ -26,7 +26,6 @@ import org.jetbrains.jet.lang.resolve.BindingTrace; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.*; -import java.util.Collections; import java.util.List; import java.util.Set; @@ -224,7 +223,7 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite { } @Override - public ClassObjectStatus setClassObjectDescriptor(@NotNull final MutableClassDescriptorLite classObjectDescriptor) { + public ClassObjectStatus setClassObjectDescriptor(@NotNull MutableClassDescriptorLite classObjectDescriptor) { ClassObjectStatus r = superBuilder.setClassObjectDescriptor(classObjectDescriptor); if (r != ClassObjectStatus.OK) { return r; @@ -232,19 +231,7 @@ public class MutableClassDescriptor extends MutableClassDescriptorLite { // Members of the class object are accessible from the class // The scope must be lazy, because classObjectDescriptor may not by fully built yet - scopeForMemberResolution.importScope(new AbstractScopeAdapter() { - @NotNull - @Override - protected JetScope getWorkerScope() { - return classObjectDescriptor.getDefaultType().getMemberScope(); - } - - @NotNull - @Override - public List getImplicitReceiversHierarchy() { - return Collections.singletonList(classObjectDescriptor.getThisAsReceiverParameter()); - } - }); + scopeForMemberResolution.importScope(new ClassObjectMixinScope(classObjectDescriptor)); return ClassObjectStatus.OK; } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java index d0d4e108a57..57079753619 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/lazy/descriptors/LazyClassDescriptor.java @@ -206,12 +206,16 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements LazyDesc thisScope.addLabeledDeclaration(this); thisScope.changeLockLevel(WritableScope.LockLevel.READING); + ClassDescriptor classObject = getClassObjectDescriptor(); + JetScope classObjectAdapterScope = (classObject != null) ? new ClassObjectMixinScope(classObject) : JetScope.EMPTY; + return new ChainedScope( this, "ScopeForMemberDeclarationResolution: " + getName(), thisScope, getScopeForMemberLookup(), - getScopeForClassHeaderResolution()); + getScopeForClassHeaderResolution(), + classObjectAdapterScope); } @NotNull diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/ClassObjectMixinScope.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/ClassObjectMixinScope.java new file mode 100644 index 00000000000..ea75f986945 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/scopes/ClassObjectMixinScope.java @@ -0,0 +1,48 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.scopes; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.ClassDescriptor; +import org.jetbrains.jet.lang.descriptors.ReceiverParameterDescriptor; + +import java.util.Collections; +import java.util.List; + +/** + * Members of the class object are accessible from the class. + * Scope lazily delegates requests to class object scope. + */ +public class ClassObjectMixinScope extends AbstractScopeAdapter { + private final ClassDescriptor classObjectDescriptor; + + public ClassObjectMixinScope(ClassDescriptor classObjectDescriptor) { + this.classObjectDescriptor = classObjectDescriptor; + } + + @NotNull + @Override + protected JetScope getWorkerScope() { + return classObjectDescriptor.getDefaultType().getMemberScope(); + } + + @NotNull + @Override + public List getImplicitReceiversHierarchy() { + return Collections.singletonList(classObjectDescriptor.getThisAsReceiverParameter()); + } +} diff --git a/compiler/testData/loadKotlin/class/ClassMemberConflict.kt b/compiler/testData/loadKotlin/class/ClassMemberConflict.kt new file mode 100644 index 00000000000..b69b0fd9e0e --- /dev/null +++ b/compiler/testData/loadKotlin/class/ClassMemberConflict.kt @@ -0,0 +1,44 @@ +package test + +class ConstructorTypeParamClassObjectTypeConflict { + class object { + trait test + } + + val some: test? = null +} + +class ConstructorTypeParamClassObjectConflict { + class object { + val test = 12 + } + + val some = test +} + +class TestConstructorParamClassObjectConflict(test: String) { + class object { + val test = 12 + } + + val some = test +} + + +class TestConstructorValClassObjectConflict(val test: String) { + class object { + val test = 12 + } + + val some = test +} + +class TestClassObjectAndClassConflict { + class object { + val bla = 12 + } + + val bla = "More" + + val some = bla +} \ No newline at end of file diff --git a/compiler/testData/loadKotlin/class/ClassMemberConflict.txt b/compiler/testData/loadKotlin/class/ClassMemberConflict.txt new file mode 100644 index 00000000000..93cb14458bc --- /dev/null +++ b/compiler/testData/loadKotlin/class/ClassMemberConflict.txt @@ -0,0 +1,66 @@ +package test + +internal final class ConstructorTypeParamClassObjectConflict { + /*primary*/ public constructor ConstructorTypeParamClassObjectConflict() + internal final val some: jet.Int + internal final fun (): jet.Int + + internal class object { + /*primary*/ private constructor () + internal final val test: jet.Int + internal final fun (): jet.Int + } +} + +internal final class ConstructorTypeParamClassObjectTypeConflict { + /*primary*/ public constructor ConstructorTypeParamClassObjectTypeConflict() + internal final val some: test? + internal final fun (): test? + + internal class object { + /*primary*/ private constructor () + + internal trait test { + } + } +} + +internal final class TestClassObjectAndClassConflict { + /*primary*/ public constructor TestClassObjectAndClassConflict() + internal final val bla: jet.String + internal final fun (): jet.String + internal final val some: jet.String + internal final fun (): jet.String + + internal class object { + /*primary*/ private constructor () + internal final val bla: jet.Int + internal final fun (): jet.Int + } +} + +internal final class TestConstructorParamClassObjectConflict { + /*primary*/ public constructor TestConstructorParamClassObjectConflict(/*0*/ test: jet.String) + internal final val some: jet.String + internal final fun (): jet.String + + internal class object { + /*primary*/ private constructor () + internal final val test: jet.Int + internal final fun (): jet.Int + } +} + +internal final class TestConstructorValClassObjectConflict { + /*primary*/ public constructor TestConstructorValClassObjectConflict(/*0*/ test: jet.String) + internal final val some: jet.String + internal final fun (): jet.String + internal final val test: jet.String + internal final fun (): jet.String + + internal class object { + /*primary*/ private constructor () + internal final val test: jet.Int + internal final fun (): jet.Int + } +} diff --git a/compiler/testData/loadKotlin/classObject/ClassObjectPropertyInClass.kt b/compiler/testData/loadKotlin/classObject/ClassObjectPropertyInClass.kt new file mode 100644 index 00000000000..9096414a0d5 --- /dev/null +++ b/compiler/testData/loadKotlin/classObject/ClassObjectPropertyInClass.kt @@ -0,0 +1,9 @@ +package test + +class A { + class object { + val some = 1 + } + + val other = some +} \ No newline at end of file diff --git a/compiler/testData/loadKotlin/classObject/ClassObjectPropertyInClass.txt b/compiler/testData/loadKotlin/classObject/ClassObjectPropertyInClass.txt new file mode 100644 index 00000000000..8396336163f --- /dev/null +++ b/compiler/testData/loadKotlin/classObject/ClassObjectPropertyInClass.txt @@ -0,0 +1,13 @@ +package test + +internal final class A { + /*primary*/ public constructor A() + internal final val other: jet.Int + internal final fun (): jet.Int + + internal class object { + /*primary*/ private constructor () + internal final val some: jet.Int + internal final fun (): jet.Int + } +} diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadCompiledKotlinTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadCompiledKotlinTestGenerated.java index a7eb520a901..191e3bb70de 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadCompiledKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadCompiledKotlinTestGenerated.java @@ -58,6 +58,11 @@ public class LoadCompiledKotlinTestGenerated extends AbstractLoadCompiledKotlinT doTestWithAccessors("compiler/testData/loadKotlin/class/ClassInnerClass.kt"); } + @TestMetadata("ClassMemberConflict.kt") + public void testClassMemberConflict() throws Exception { + doTestWithAccessors("compiler/testData/loadKotlin/class/ClassMemberConflict.kt"); + } + @TestMetadata("ClassOutParam.kt") public void testClassOutParam() throws Exception { doTestWithAccessors("compiler/testData/loadKotlin/class/ClassOutParam.kt"); @@ -259,6 +264,11 @@ public class LoadCompiledKotlinTestGenerated extends AbstractLoadCompiledKotlinT doTestWithAccessors("compiler/testData/loadKotlin/classObject/ClassObjectExtendsTraitWithTP.kt"); } + @TestMetadata("ClassObjectPropertyInClass.kt") + public void testClassObjectPropertyInClass() throws Exception { + doTestWithAccessors("compiler/testData/loadKotlin/classObject/ClassObjectPropertyInClass.kt"); + } + @TestMetadata("InnerClassInClassObject.kt") public void testInnerClassInClassObject() throws Exception { doTestWithAccessors("compiler/testData/loadKotlin/classObject/InnerClassInClassObject.kt"); diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java index f7e249dfbe0..4bf970ac668 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java @@ -60,6 +60,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/class/ClassInnerClass.kt"); } + @TestMetadata("ClassMemberConflict.kt") + public void testClassMemberConflict() throws Exception { + doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/class/ClassMemberConflict.kt"); + } + @TestMetadata("ClassOutParam.kt") public void testClassOutParam() throws Exception { doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/class/ClassOutParam.kt"); @@ -261,6 +266,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/classObject/ClassObjectExtendsTraitWithTP.kt"); } + @TestMetadata("ClassObjectPropertyInClass.kt") + public void testClassObjectPropertyInClass() throws Exception { + doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/classObject/ClassObjectPropertyInClass.kt"); + } + @TestMetadata("InnerClassInClassObject.kt") public void testInnerClassInClassObject() throws Exception { doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/classObject/InnerClassInClassObject.kt"); diff --git a/idea/testData/completion/basic/common/classObjectElementsInClass.kt b/idea/testData/completion/basic/common/classObjectElementsInClass.kt new file mode 100644 index 00000000000..ff9b87cf36a --- /dev/null +++ b/idea/testData/completion/basic/common/classObjectElementsInClass.kt @@ -0,0 +1,13 @@ +class Some { + class object { + val coProp = 12 + + fun coFun = 12 + } + + fun some() { + val a = co + } +} + +// EXIST: coProp, coFun \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/completion/JetBasicJSCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JetBasicJSCompletionTestGenerated.java index 8671b450cf2..d842aa95c82 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetBasicJSCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/JetBasicJSCompletionTestGenerated.java @@ -79,6 +79,11 @@ public class JetBasicJSCompletionTestGenerated extends AbstractJetJSCompletionTe doTest("idea/testData/completion/basic/common/CallLocalLambda.kt"); } + @TestMetadata("classObjectElementsInClass.kt") + public void testClassObjectElementsInClass() throws Exception { + doTest("idea/testData/completion/basic/common/classObjectElementsInClass.kt"); + } + @TestMetadata("ClassRedeclaration1.kt") public void testClassRedeclaration1() throws Exception { doTest("idea/testData/completion/basic/common/ClassRedeclaration1.kt"); diff --git a/idea/tests/org/jetbrains/jet/completion/JetBasicJavaCompletionTestGenerated.java b/idea/tests/org/jetbrains/jet/completion/JetBasicJavaCompletionTestGenerated.java index dd6a7d5a412..8dad2867c6c 100644 --- a/idea/tests/org/jetbrains/jet/completion/JetBasicJavaCompletionTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/completion/JetBasicJavaCompletionTestGenerated.java @@ -79,6 +79,11 @@ public class JetBasicJavaCompletionTestGenerated extends AbstractJavaCompletionT doTest("idea/testData/completion/basic/common/CallLocalLambda.kt"); } + @TestMetadata("classObjectElementsInClass.kt") + public void testClassObjectElementsInClass() throws Exception { + doTest("idea/testData/completion/basic/common/classObjectElementsInClass.kt"); + } + @TestMetadata("ClassRedeclaration1.kt") public void testClassRedeclaration1() throws Exception { doTest("idea/testData/completion/basic/common/ClassRedeclaration1.kt");