@@ -108,11 +108,8 @@ class ClasspathIndexer {
108108 index.addSourceJar(directory.absolutePath)
109109 }
110110
111- private fun detectExtensionReceiver (
112- extensionFunctionNames : Set <String >,
113- method : MethodInfo
114- ): String? {
115- if (method.name !in extensionFunctionNames) return null
111+ private fun detectExtensionReceiver (method : MethodInfo ): String? {
112+ if (! method.isExtension) return null
116113 if (method.parameters.isEmpty()) return null
117114 return method.parameters.first().type
118115 }
@@ -160,7 +157,7 @@ class ClasspathIndexer {
160157 }
161158 if (method.name == " <clinit>" ) continue
162159
163- val extensionReceiver = detectExtensionReceiver(classInfo.extensionFunctionNames, method)
160+ val extensionReceiver = detectExtensionReceiver(method)
164161
165162 val params = if (extensionReceiver != null && method.parameters.isNotEmpty()) {
166163 method.parameters.drop(1 )
@@ -294,28 +291,40 @@ internal object ClassFileReader {
294291
295292 val attributesCount = readU2(bytes, offset)
296293 offset + = 2
297- val extensionNames = mutableSetOf <String >()
294+ var extensionFunctions = emptyMap <String , List < Int > >()
298295 for (i in 0 until attributesCount) {
299296 val attrNameIndex = readU2(bytes, offset)
300297 offset + = 2
301298 val attrLength = readU4(bytes, offset)
302299 offset + = 4
303300 val attrName = constantPool.getUtf8(attrNameIndex)
304301 if (attrName == " RuntimeVisibleAnnotations" ) {
305- val parsed = parseKotlinMetadataExtensions(bytes, offset, attrLength, constantPool)
306- extensionNames.addAll(parsed)
302+ extensionFunctions = parseKotlinMetadataExtensions(bytes, offset, attrLength, constantPool)
307303 }
308304 offset + = attrLength
309305 }
310306
307+ val markedMethods = if (extensionFunctions.isNotEmpty()) {
308+ val remaining = extensionFunctions.mapValues { it.value.toMutableList() }.toMutableMap()
309+ methods.map { method ->
310+ val valueCounts = remaining[method.name] ? : return @map method
311+ if (method.parameters.isEmpty()) return @map method
312+ val idx = valueCounts.indexOf(method.parameters.size - 1 )
313+ if (idx < 0 ) return @map method
314+ valueCounts.removeAt(idx)
315+ method.copy(isExtension = true )
316+ }
317+ } else {
318+ methods
319+ }
320+
311321 return ClassInfo (
312322 kind = parseClassKind(accessFlags),
313323 visibility = parseVisibility(accessFlags),
314324 typeParameters = emptyList(),
315325 superTypes = superTypes,
316- methods = methods,
317- fields = fields,
318- extensionFunctionNames = extensionNames
326+ methods = markedMethods,
327+ fields = fields
319328 )
320329 }
321330
@@ -324,10 +333,10 @@ internal object ClassFileReader {
324333 offset : Int ,
325334 length : Int ,
326335 constantPool : ConstantPool
327- ): Set <String > {
336+ ): Map <String , MutableList < Int > > {
328337 try {
329338 val endOffset = offset + length
330- if (offset >= bytes.size) return emptySet ()
339+ if (offset >= bytes.size) return emptyMap ()
331340 val numAnnotations = readU2(bytes, offset)
332341 var pos = offset + 2
333342
@@ -373,12 +382,12 @@ internal object ClassFileReader {
373382
374383 if (d1Bytes.isNotEmpty() && d2Strings.isNotEmpty()) {
375384 val combined = d1Bytes.fold(ByteArray (0 )) { acc, b -> acc + b }
376- return extractExtensionFunctionNames (combined, d2Strings)
385+ return extractExtensionFunctions (combined, d2Strings)
377386 }
378387 }
379388 } catch (_: Exception ) {
380389 }
381- return emptySet ()
390+ return emptyMap ()
382391 }
383392
384393 private fun parseAnnotationArrayOfStrings (
@@ -438,8 +447,8 @@ internal object ClassFileReader {
438447 }
439448 }
440449
441- private fun extractExtensionFunctionNames (d1 : ByteArray , d2 : List <String >): Set <String > {
442- val extensionNames = mutableSetOf <String >()
450+ private fun extractExtensionFunctions (d1 : ByteArray , d2 : List <String >): Map <String , MutableList < Int > > {
451+ val extensionFunctions = mutableMapOf <String , MutableList < Int > >()
443452 try {
444453 var pos = 0
445454 while (pos < d1.size) {
@@ -464,6 +473,7 @@ internal object ClassFileReader {
464473 val msgEnd = pos + msgLen
465474 var nameIndex = - 1
466475 var hasReceiver = false
476+ var valueParamCount = 0
467477 var innerPos = pos
468478
469479 while (innerPos < msgEnd) {
@@ -489,6 +499,7 @@ internal object ClassFileReader {
489499 2 -> {
490500 val (innerLen, np) = readVarInt(d1, innerPos)
491501 innerPos = np
502+ if (innerField == 5 ) valueParamCount++
492503 if (innerField == 6 ) hasReceiver = true
493504 innerPos + = innerLen
494505 }
@@ -498,7 +509,9 @@ internal object ClassFileReader {
498509 }
499510
500511 if (hasReceiver && nameIndex >= 0 && nameIndex < d2.size) {
501- extensionNames.add(d2[nameIndex])
512+ extensionFunctions
513+ .getOrPut(d2[nameIndex]) { mutableListOf () }
514+ .add(valueParamCount)
502515 }
503516 pos = msgEnd
504517 } else {
@@ -511,7 +524,7 @@ internal object ClassFileReader {
511524 }
512525 } catch (_: Exception ) {
513526 }
514- return extensionNames
527+ return extensionFunctions
515528 }
516529
517530 private fun readVarInt (bytes : ByteArray , startPos : Int ): Pair <Int , Int > {
@@ -841,8 +854,7 @@ data class ClassInfo(
841854 val typeParameters : List <String >,
842855 val superTypes : List <String >,
843856 val methods : List <MethodInfo >,
844- val fields : List <FieldInfo >,
845- val extensionFunctionNames : Set <String > = emptySet()
857+ val fields : List <FieldInfo >
846858) {
847859 companion object {
848860 val EMPTY = ClassInfo (
@@ -861,7 +873,8 @@ data class MethodInfo(
861873 val parameters : List <IndexedParameter >,
862874 val returnType : String ,
863875 val visibility : Visibility ,
864- val typeParameters : List <String >
876+ val typeParameters : List <String >,
877+ val isExtension : Boolean = false
865878)
866879
867880data class FieldInfo (
0 commit comments