diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index cb9a78c81cd..a81e3b55077 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -63,27 +63,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -101,4 +80,4 @@
-
+
\ No newline at end of file
diff --git a/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Methods.kt b/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Methods.kt
index 40dac89ef99..7fb1583285e 100644
--- a/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Methods.kt
+++ b/compiler/resolution.common.jvm/src/org/jetbrains/kotlin/load/java/structure/impl/classFiles/Methods.kt
@@ -59,24 +59,36 @@ abstract class BinaryJavaMethodBase(
val isInnerClassConstructor = isConstructor && containingClass.outerClass != null && !containingClass.isStatic
val isEnumConstructor = containingClass.isEnum && isConstructor
+ val methodInfoFromDescriptor = parseMethodDescription(desc, parentContext, signatureParser).let {
+ when {
+ isEnumConstructor ->
+ // skip ordinal/name parameters for enum constructors
+ MethodInfo(it.returnType, it.typeParameters, it.valueParameterTypes.drop(2))
+ isInnerClassConstructor ->
+ // omit synthetic inner class constructor parameter
+ MethodInfo(it.returnType, it.typeParameters, it.valueParameterTypes.drop(1))
+ else -> it
+ }
+ }
val info: MethodInfo =
if (signature != null) {
val contextForMethod = parentContext.copyForMember()
- parseMethodSignature(signature, signatureParser, contextForMethod).also {
+ val methodInforFromSignature = parseMethodSignature(signature, signatureParser, contextForMethod).also {
contextForMethod.addTypeParameters(it.typeParameters)
}
- } else
- parseMethodDescription(desc, parentContext, signatureParser).let {
- when {
- isEnumConstructor ->
- // skip ordinal/name parameters for enum constructors
- MethodInfo(it.returnType, it.typeParameters, it.valueParameterTypes.drop(2))
- isInnerClassConstructor ->
- // omit synthetic inner class constructor parameter
- MethodInfo(it.returnType, it.typeParameters, it.valueParameterTypes.drop(1))
- else -> it
- }
+ // JVM specs allows disagreements in parameters between signature and descriptor/serialized method. In particular the
+ // situation was detected on Scala stdlib (see #KT-3825 for some details).
+ // But in our implementation we are using the parameter infos read here as a "master" so if signature has less params
+ // than the descriptor, we need get missing parameter infos from somewhere.
+ // Since the known cases are rare, it was decided to keep it simple for now and only cover this particular case.
+ if (methodInforFromSignature.valueParameterTypes.count() < methodInfoFromDescriptor.valueParameterTypes.count()) {
+ methodInfoFromDescriptor
+ } else {
+ methodInforFromSignature
}
+ } else {
+ methodInfoFromDescriptor
+ }
val parameterTypes = info.valueParameterTypes
val paramCount = parameterTypes.size
diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CustomGeneratedClassesTest.kt b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CustomGeneratedClassesTest.kt
new file mode 100644
index 00000000000..41645bb9423
--- /dev/null
+++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CustomGeneratedClassesTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
+ * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
+ */
+
+package org.jetbrains.kotlin.jvm.compiler
+
+import com.intellij.testFramework.BinaryLightVirtualFile
+import junit.framework.TestCase
+import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryClassSignatureParser
+import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryJavaClass
+import org.jetbrains.kotlin.load.java.structure.impl.classFiles.ClassifierResolutionContext
+import org.jetbrains.kotlin.name.FqName
+import org.jetbrains.org.objectweb.asm.ClassWriter
+import org.jetbrains.org.objectweb.asm.Opcodes
+import org.jetbrains.org.objectweb.asm.tree.ClassNode
+import org.jetbrains.org.objectweb.asm.tree.MethodNode
+import org.junit.Test
+
+class CustomGeneratedClassesTest : TestCase() {
+
+ @Test
+ fun testEmulatedScalaStdlibSyntheticMethodLoading() {
+ // #KT-38325 and #KT-39799
+ val classFqn = "org/jetbrains/kotlin/compiler/test/GeneratedScalalikeTraversableOncePart"
+
+ val classNode = ClassNode(Opcodes.API_VERSION).apply {
+ version = Opcodes.V1_6
+ access = Opcodes.ACC_PUBLIC
+ name = classFqn
+ signature = "L$classFqn;"
+ superName = "java/lang/Object"
+ methods.add(
+ // The root of the problem described in the #KT-38325 and #KT-39799 is the presence of a method with signature and descriptor
+ // disagreeing on the number of parameters. Here the method with the similar structure is created
+ MethodNode(
+ Opcodes.API_VERSION,
+ Opcodes.ACC_PRIVATE,
+ "reverser\$2",
+ "(Ljava/lang/Object;)L$classFqn\$reverser\$1\$;",
+ "()L$classFqn\$reverser\$1\$;",
+ null
+ ).apply {
+ visitParameter("a", 0)
+ }
+ )
+ }
+
+ val classWriter = ClassWriter(0).also {
+ classNode.accept(it)
+ }
+
+ // This is the actual test. Without the relevant fix, this call throws "No parameter with index 0-0" error
+ BinaryJavaClass(
+ BinaryLightVirtualFile("$classFqn.class", classWriter.toByteArray()),
+ FqName(classFqn.replace('/', '.')),
+ ClassifierResolutionContext { null },
+ BinaryClassSignatureParser(),
+ outerClass = null
+ )
+ }
+}
\ No newline at end of file