@@ -3,6 +3,8 @@ package com.github.codeql
33import com.github.codeql.utils.substituteTypeArguments
44import com.semmle.extractor.java.OdasaOutput
55import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
6+ import org.jetbrains.kotlin.backend.common.lower.parents
7+ import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
68import org.jetbrains.kotlin.backend.jvm.codegen.isRawType
79import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
810import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -140,6 +142,24 @@ open class KotlinUsesExtractor(
140142 } ? : argsIncludingOuterClasses
141143 }
142144
145+ // The Kotlin compiler internal representation of Outer<A, B>.Inner<C, D>.InnerInner<E, F> is InnerInner<E, F, C, D, A, B>. This function returns [A, B, C, D, E, F].
146+ fun orderTypeArgsLeftToRight (c : IrClass , argsIncludingOuterClasses : List <IrTypeArgument >? ): List <IrTypeArgument >? {
147+ if (argsIncludingOuterClasses.isNullOrEmpty())
148+ return argsIncludingOuterClasses
149+ val ret = ArrayList <IrTypeArgument >()
150+ // Iterate over nested inner classes starting at `c`'s surrounding top-level or static nested class and ending at `c`, from the outermost inwards:
151+ val parentsList = c.parentsWithSelf.toList()
152+ val firstOuterClassIdx = parentsList.indexOfFirst { it is IrClass && ! it.isInner }
153+ val truncatedParents = if (firstOuterClassIdx == - 1 ) parentsList else parentsList.subList(0 , firstOuterClassIdx + 1 )
154+ for (parent in truncatedParents.reversed()) {
155+ if (parent is IrClass ) {
156+ val firstArgIdx = argsIncludingOuterClasses.size - (ret.size + parent.typeParameters.size)
157+ ret.addAll(argsIncludingOuterClasses.subList(firstArgIdx, firstArgIdx + parent.typeParameters.size))
158+ }
159+ }
160+ return ret
161+ }
162+
143163 // `typeArgs` can be null to describe a raw generic type.
144164 // For non-generic types it will be zero-length list.
145165 fun useClassInstance (c : IrClass , typeArgs : List <IrTypeArgument >? , inReceiverContext : Boolean = false): UseClassInstanceResult {
@@ -199,7 +219,7 @@ open class KotlinUsesExtractor(
199219 // For all purposes ignore type arguments relating to outer classes.
200220 val typeArgs = removeOuterClassTypeArgs(c, argsIncludingOuterClasses)
201221
202- val classLabelResult = getClassLabel(c, typeArgs )
222+ val classLabelResult = getClassLabel(c, argsIncludingOuterClasses )
203223
204224 var instanceSeenBefore = true
205225
@@ -733,10 +753,10 @@ class X {
733753 /* *
734754 * This returns the `X` in c's label `@"class;X"`.
735755 *
736- * `typeArgs ` can be null to describe a raw generic type.
756+ * `argsIncludingOuterClasses ` can be null to describe a raw generic type.
737757 * For non-generic types it will be zero-length list.
738758 */
739- private fun getUnquotedClassLabel (c : IrClass , typeArgs : List <IrTypeArgument >? ): ClassLabelResults {
759+ private fun getUnquotedClassLabel (c : IrClass , argsIncludingOuterClasses : List <IrTypeArgument >? ): ClassLabelResults {
740760 val pkg = c.packageFqName?.asString() ? : " "
741761 val cls = c.name.asString()
742762 val label = when (val parent = c.parent) {
@@ -753,14 +773,15 @@ class X {
753773 }
754774 }
755775
756- val typeArgLabels = typeArgs?.map { getTypeArgumentLabel(it) }
776+ val reorderedArgs = orderTypeArgsLeftToRight(c, argsIncludingOuterClasses)
777+ val typeArgLabels = reorderedArgs?.map { getTypeArgumentLabel(it) }
757778 val typeArgsShortName =
758779 if (typeArgLabels == null )
759780 " <>"
760781 else if (typeArgLabels.isEmpty())
761782 " "
762783 else
763- typeArgLabels.joinToString(prefix = " <" , postfix = " >" , separator = " ," ) { it.shortName }
784+ typeArgLabels.takeLast(c.typeParameters.size). joinToString(prefix = " <" , postfix = " >" , separator = " ," ) { it.shortName }
764785
765786 return ClassLabelResults (
766787 label + (typeArgLabels?.joinToString(separator = " " ) { " ;{${it.id} }" } ? : " <>" ),
@@ -770,12 +791,12 @@ class X {
770791
771792 // `args` can be null to describe a raw generic type.
772793 // For non-generic types it will be zero-length list.
773- fun getClassLabel (c : IrClass , typeArgs : List <IrTypeArgument >? ): ClassLabelResults {
794+ fun getClassLabel (c : IrClass , argsIncludingOuterClasses : List <IrTypeArgument >? ): ClassLabelResults {
774795 if (c.isAnonymousObject) {
775796 logger.warn(Severity .ErrorSevere , " Label generation should not be requested for an anonymous class" )
776797 }
777798
778- val unquotedLabel = getUnquotedClassLabel(c, typeArgs )
799+ val unquotedLabel = getUnquotedClassLabel(c, argsIncludingOuterClasses )
779800 return ClassLabelResults (
780801 " @\" class;${unquotedLabel.classLabel} \" " ,
781802 unquotedLabel.shortName)
0 commit comments