Fix for KT-9958: NoSuchMethodError when we call protected method from companion object
#KT-9958 Fixed
This commit is contained in:
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.psi.*;
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||||
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
import org.jetbrains.kotlin.resolve.DescriptorUtils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -51,11 +52,19 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtClassOrObject> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void generateBody() {
|
protected void generateBody() {
|
||||||
|
List<KtObjectDeclaration> companions = new ArrayList<KtObjectDeclaration>();
|
||||||
if (kind != OwnerKind.DEFAULT_IMPLS) {
|
if (kind != OwnerKind.DEFAULT_IMPLS) {
|
||||||
//generate nested classes first and only then generate class body. It necessary to access to nested CodegenContexts
|
//generate nested classes first and only then generate class body. It necessary to access to nested CodegenContexts
|
||||||
for (KtDeclaration declaration : myClass.getDeclarations()) {
|
for (KtDeclaration declaration : myClass.getDeclarations()) {
|
||||||
if (shouldProcessFirst(declaration)) {
|
if (shouldProcessFirst(declaration)) {
|
||||||
generateDeclaration(declaration);
|
//Generate companions after class body generation (need to record all synthetic accessors)
|
||||||
|
if (declaration instanceof KtObjectDeclaration && ((KtObjectDeclaration) declaration).isCompanion()) {
|
||||||
|
companions.add((KtObjectDeclaration) declaration);
|
||||||
|
CodegenUtilKt.populateCompanionBackingFieldNamesToOuterContextIfNeeded((KtObjectDeclaration) declaration, context, state);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
generateDeclaration(declaration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,6 +75,12 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtClassOrObject> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
generatePrimaryConstructorProperties();
|
||||||
|
generateConstructors();
|
||||||
|
for (KtObjectDeclaration companion : companions) {
|
||||||
|
generateDeclaration(companion);
|
||||||
|
}
|
||||||
|
|
||||||
if (!DescriptorUtils.isInterface(descriptor)) {
|
if (!DescriptorUtils.isInterface(descriptor)) {
|
||||||
for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
|
for (DeclarationDescriptor memberDescriptor : DescriptorUtils.getAllDescriptors(descriptor.getDefaultType().getMemberScope())) {
|
||||||
if (memberDescriptor instanceof CallableMemberDescriptor) {
|
if (memberDescriptor instanceof CallableMemberDescriptor) {
|
||||||
@@ -88,8 +103,10 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtClassOrObject> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void generateConstructors() {
|
||||||
|
|
||||||
generatePrimaryConstructorProperties();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean shouldProcessFirst(KtDeclaration declaration) {
|
private static boolean shouldProcessFirst(KtDeclaration declaration) {
|
||||||
|
|||||||
@@ -98,6 +98,8 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
|
|
||||||
private List<PropertyAndDefaultValue> companionObjectPropertiesToCopy;
|
private List<PropertyAndDefaultValue> companionObjectPropertiesToCopy;
|
||||||
|
|
||||||
|
private final DelegationFieldsInfo delegationFieldsInfo;
|
||||||
|
|
||||||
private final List<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>> additionalTasks =
|
private final List<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>> additionalTasks =
|
||||||
new ArrayList<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>>();
|
new ArrayList<Function2<ImplementationBodyCodegen, ClassBuilder, Unit>>();
|
||||||
|
|
||||||
@@ -112,6 +114,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
super(aClass, context, v, state, parentCodegen);
|
super(aClass, context, v, state, parentCodegen);
|
||||||
this.classAsmType = typeMapper.mapClass(descriptor);
|
this.classAsmType = typeMapper.mapClass(descriptor);
|
||||||
this.isLocal = isLocal;
|
this.isLocal = isLocal;
|
||||||
|
delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -228,7 +231,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void generateBody() {
|
protected void generateBody() {
|
||||||
super.generateBody();
|
|
||||||
if (isInterface(descriptor) && !isLocal) {
|
if (isInterface(descriptor) && !isLocal) {
|
||||||
Type defaultImplsType = state.getTypeMapper().mapDefaultImpls(descriptor);
|
Type defaultImplsType = state.getTypeMapper().mapDefaultImpls(descriptor);
|
||||||
ClassBuilder defaultImplsBuilder =
|
ClassBuilder defaultImplsBuilder =
|
||||||
@@ -237,9 +239,10 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
CodegenContext parentContext = context.getParentContext();
|
CodegenContext parentContext = context.getParentContext();
|
||||||
assert parentContext != null : "Parent context of interface declaration should not be null";
|
assert parentContext != null : "Parent context of interface declaration should not be null";
|
||||||
|
|
||||||
ClassContext defaultImplsContext = parentContext.intoClass(descriptor, OwnerKind.DEFAULT_IMPLS, state);
|
ClassContext defaultImplsContext = parentContext.intoDefaultImplsClass(descriptor, (ClassContext) context, state);
|
||||||
new InterfaceImplBodyCodegen(myClass, defaultImplsContext, defaultImplsBuilder, state, this).generate();
|
new InterfaceImplBodyCodegen(myClass, defaultImplsContext, defaultImplsBuilder, state, this).generate();
|
||||||
}
|
}
|
||||||
|
super.generateBody();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -371,24 +374,6 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
|
|
||||||
generateCompanionObjectBackingFieldCopies();
|
generateCompanionObjectBackingFieldCopies();
|
||||||
|
|
||||||
DelegationFieldsInfo delegationFieldsInfo = getDelegationFieldsInfo(myClass.getSuperTypeListEntries());
|
|
||||||
try {
|
|
||||||
lookupConstructorExpressionsInClosureIfPresent();
|
|
||||||
generatePrimaryConstructor(delegationFieldsInfo);
|
|
||||||
for (ConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) {
|
|
||||||
generateSecondaryConstructor(secondaryConstructor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (CompilationException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (ProcessCanceledException e) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
catch (RuntimeException e) {
|
|
||||||
throw new RuntimeException("Error generating constructors of class " + myClass.getName() + " with kind " + kind, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
generateTraitMethods();
|
generateTraitMethods();
|
||||||
|
|
||||||
generateDelegates(delegationFieldsInfo);
|
generateDelegates(delegationFieldsInfo);
|
||||||
@@ -410,6 +395,26 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void generateConstructors() {
|
||||||
|
try {
|
||||||
|
lookupConstructorExpressionsInClosureIfPresent();
|
||||||
|
generatePrimaryConstructor(delegationFieldsInfo);
|
||||||
|
for (ConstructorDescriptor secondaryConstructor : DescriptorUtilsKt.getSecondaryConstructors(descriptor)) {
|
||||||
|
generateSecondaryConstructor(secondaryConstructor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (CompilationException e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (ProcessCanceledException e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
catch (RuntimeException e) {
|
||||||
|
throw new RuntimeException("Error generating constructors of class " + myClass.getName() + " with kind " + kind, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isGenericToArrayPresent() {
|
private boolean isGenericToArrayPresent() {
|
||||||
Collection<FunctionDescriptor> functions =
|
Collection<FunctionDescriptor> functions =
|
||||||
descriptor.getDefaultType().getMemberScope().getContributedFunctions(Name.identifier("toArray"), NoLookupLocation.FROM_BACKEND);
|
descriptor.getDefaultType().getMemberScope().getContributedFunctions(Name.identifier("toArray"), NoLookupLocation.FROM_BACKEND);
|
||||||
|
|||||||
@@ -17,8 +17,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen
|
package org.jetbrains.kotlin.codegen
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
||||||
|
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo
|
import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature.SpecialSignatureInfo
|
||||||
|
import org.jetbrains.kotlin.psi.KtObjectDeclaration
|
||||||
|
import org.jetbrains.kotlin.psi.KtProperty
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
|
import org.jetbrains.kotlin.types.ErrorUtils
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.org.objectweb.asm.Label
|
import org.jetbrains.org.objectweb.asm.Label
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
@@ -68,3 +75,23 @@ fun generateNullCheckForNonSafeAs(
|
|||||||
public fun SpecialSignatureInfo.replaceValueParametersIn(sourceSignature: String?): String?
|
public fun SpecialSignatureInfo.replaceValueParametersIn(sourceSignature: String?): String?
|
||||||
= valueParametersSignature?.let { sourceSignature?.replace("^\\(.*\\)".toRegex(), "($it)") }
|
= valueParametersSignature?.let { sourceSignature?.replace("^\\(.*\\)".toRegex(), "($it)") }
|
||||||
|
|
||||||
|
fun populateCompanionBackingFieldNamesToOuterContextIfNeeded(companion: KtObjectDeclaration, outerContext: FieldOwnerContext<*>, state: GenerationState) {
|
||||||
|
val descriptor = state.bindingContext.get(BindingContext.CLASS, companion)
|
||||||
|
|
||||||
|
if (descriptor == null || ErrorUtils.isError(descriptor)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!AsmUtil.isCompanionObjectWithBackingFieldsInOuter(descriptor)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val properties = companion.declarations.filterIsInstance<KtProperty>()
|
||||||
|
|
||||||
|
properties.forEach {
|
||||||
|
val variableDescriptor = state.bindingContext.get(BindingContext.VARIABLE, it)
|
||||||
|
if (variableDescriptor is PropertyDescriptor) {
|
||||||
|
outerContext.getFieldName(variableDescriptor, it.hasDelegate())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -266,6 +266,10 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
|||||||
return new MultifileClassFacadeContext(descriptor, this, multifileClassType, filePartType);
|
return new MultifileClassFacadeContext(descriptor, this, multifileClassType, filePartType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ClassContext intoDefaultImplsClass(ClassDescriptor descriptor, ClassContext interfaceContext, GenerationState state) {
|
||||||
|
return new DefaultImplsClassContext(state.getTypeMapper(), descriptor, OwnerKind.DEFAULT_IMPLS, this, null, interfaceContext);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
|
public ClassContext intoClass(ClassDescriptor descriptor, OwnerKind kind, GenerationState state) {
|
||||||
if (descriptor.isCompanionObject()) {
|
if (descriptor.isCompanionObject()) {
|
||||||
@@ -624,7 +628,7 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
|
protected CodegenContext findChildContext(@NotNull DeclarationDescriptor child) {
|
||||||
return childContexts == null ? null : childContexts.get(child);
|
return childContexts == null ? null : childContexts.get(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2015 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.kotlin.codegen.context
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.codegen.OwnerKind
|
||||||
|
import org.jetbrains.kotlin.codegen.state.JetTypeMapper
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
|
||||||
|
class DefaultImplsClassContext(
|
||||||
|
typeMapper: JetTypeMapper,
|
||||||
|
contextDescriptor: ClassDescriptor,
|
||||||
|
contextKind: OwnerKind,
|
||||||
|
parentContext: CodegenContext<*>?,
|
||||||
|
localLookup: ((DeclarationDescriptor) -> Boolean)?,
|
||||||
|
val interfaceContext: ClassContext
|
||||||
|
) : ClassContext(typeMapper, contextDescriptor, contextKind, parentContext, localLookup) {
|
||||||
|
|
||||||
|
override fun getCompanionObjectContext(): CodegenContext<*>? {
|
||||||
|
return interfaceContext.companionObjectContext
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package a
|
||||||
|
|
||||||
|
import b.*
|
||||||
|
|
||||||
|
class B {
|
||||||
|
companion object : A() {}
|
||||||
|
|
||||||
|
init {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
B()
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package b
|
||||||
|
|
||||||
|
var result = "fail"
|
||||||
|
|
||||||
|
abstract class A {
|
||||||
|
protected fun foo() {
|
||||||
|
result = "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package a
|
||||||
|
|
||||||
|
import b.*
|
||||||
|
|
||||||
|
interface B {
|
||||||
|
companion object : A() {}
|
||||||
|
|
||||||
|
fun test() {
|
||||||
|
foo()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class C : B
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
C().test()
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package b
|
||||||
|
|
||||||
|
var result = "fail"
|
||||||
|
|
||||||
|
abstract class A {
|
||||||
|
protected fun foo() {
|
||||||
|
result = "OK"
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
@@ -107,6 +107,18 @@ public class BlackBoxMultiFileCodegenTestGenerated extends AbstractBlackBoxCodeg
|
|||||||
doTestMultiFile(fileName);
|
doTestMultiFile(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt9958")
|
||||||
|
public void testKt9958() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/kt9958/");
|
||||||
|
doTestMultiFile(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt9958Interface")
|
||||||
|
public void testKt9958Interface() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/kt9958Interface/");
|
||||||
|
doTestMultiFile(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("mainInFiles")
|
@TestMetadata("mainInFiles")
|
||||||
public void testMainInFiles() throws Exception {
|
public void testMainInFiles() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/mainInFiles/");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxMultiFile/mainInFiles/");
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
a java.lang.Deprecated 0
|
a java.lang.Deprecated 0
|
||||||
p org.test 0
|
p org.test 0
|
||||||
c 0 0/SomeClass$Companion
|
|
||||||
c 0 0/SomeClass$SomeInnerObject
|
c 0 0/SomeClass$SomeInnerObject
|
||||||
c 0 0/SomeClass$InnerClass
|
c 0 0/SomeClass$InnerClass
|
||||||
c 0 0/SomeClass$InnerClass$InnerClassInInnerClass
|
c 0 0/SomeClass$InnerClass$InnerClassInInnerClass
|
||||||
c 0 0/SomeClass$NestedClass
|
c 0 0/SomeClass$NestedClass
|
||||||
|
c 0 0/SomeClass$Companion
|
||||||
|
|||||||
Reference in New Issue
Block a user