@@ -2,6 +2,7 @@ package com.github.codeql
22
33import com.github.codeql.utils.*
44import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
5+ import com.github.codeql.utils.versions.getFileClassFqName
56import com.github.codeql.utils.versions.getKotlinType
67import com.github.codeql.utils.versions.isRawType
78import com.semmle.extractor.java.OdasaOutput
@@ -71,18 +72,41 @@ open class KotlinUsesExtractor(
7172 TypeResult (fakeKotlinType(), " " , " " )
7273 )
7374
75+ fun useFileClassType (fqName : FqName ) = TypeResults (
76+ TypeResult (extractFileClass(fqName), " " , " " ),
77+ TypeResult (fakeKotlinType(), " " , " " )
78+ )
79+
80+ private fun useFileClassType (pkg : String , jvmName : String ) = TypeResults (
81+ TypeResult (extractFileClass(pkg, jvmName), " " , " " ),
82+ TypeResult (fakeKotlinType(), " " , " " )
83+ )
84+
7485 fun extractFileClass (f : IrFile ): Label <out DbClassorinterface > {
7586 val pkg = f.fqName.asString()
7687 val jvmName = getFileClassName(f)
88+ val id = extractFileClass(pkg, jvmName)
89+ if (tw.lm.fileClassLocationsExtracted.add(f)) {
90+ val fileId = tw.mkFileId(f.path, false )
91+ val locId = tw.getWholeFileLocation(fileId)
92+ tw.writeHasLocation(id, locId)
93+ }
94+ return id
95+ }
96+
97+ private fun extractFileClass (fqName : FqName ): Label <out DbClassorinterface > {
98+ val pkg = if (fqName.isRoot()) " " else fqName.parent().asString()
99+ val jvmName = fqName.shortName().asString()
100+ return extractFileClass(pkg, jvmName)
101+ }
102+
103+ private fun extractFileClass (pkg : String , jvmName : String ): Label <out DbClassorinterface > {
77104 val qualClassName = if (pkg.isEmpty()) jvmName else " $pkg .$jvmName "
78105 val label = " @\" class;$qualClassName \" "
79106 val id: Label <DbClassorinterface > = tw.getLabelFor(label) {
80- val fileId = tw.mkFileId(f.path, false )
81- val locId = tw.getWholeFileLocation(fileId)
82107 val pkgId = extractPackage(pkg)
83108 tw.writeClasses_or_interfaces(it, jvmName, pkgId, it)
84109 tw.writeFile_class(it)
85- tw.writeHasLocation(it, locId)
86110
87111 addModifiers(it, " public" , " final" )
88112 }
@@ -250,7 +274,11 @@ open class KotlinUsesExtractor(
250274 is IrClass -> extractExternalClassLater(parent)
251275 is IrFunction -> extractExternalEnclosingClassLater(parent)
252276 is IrFile -> logger.error(" extractExternalEnclosingClassLater but no enclosing class." )
253- else -> logger.error(" Unrecognised extractExternalEnclosingClassLater: " + d.javaClass)
277+ is IrExternalPackageFragment -> {
278+ // The parent is a (multi)file class. We don't need
279+ // extract it separately.
280+ }
281+ else -> logger.error(" Unrecognised extractExternalEnclosingClassLater ${parent.javaClass} for ${d.javaClass} " )
254282 }
255283 }
256284
@@ -293,7 +321,17 @@ open class KotlinUsesExtractor(
293321
294322 private fun extractFunctionLaterIfExternalFileMember (f : IrFunction ) {
295323 if (isExternalFileClassMember(f)) {
296- extractExternalClassLater(f.parentAsClass)
324+ val p = f.parent
325+ when (p) {
326+ is IrClass -> extractExternalClassLater(p)
327+ is IrExternalPackageFragment -> {
328+ // The parent is a (multi)file class. We don't need
329+ // extract it separately.
330+ }
331+ else -> {
332+ logger.warn(" Unexpected parent type ${p.javaClass} for external file class member" )
333+ }
334+ }
297335 (f as ? IrSimpleFunction )?.correspondingPropertySymbol?.let {
298336 extractPropertyLaterIfExternalFileMember(it.owner)
299337 // No need to extract the function specifically, as the property's
@@ -761,6 +799,41 @@ open class KotlinUsesExtractor(
761799 }
762800 }
763801
802+ private fun parentOf (d : IrDeclaration ): IrDeclarationParent {
803+ if (d is IrField ) {
804+ return getFieldParent(d)
805+ }
806+ return d.parent
807+ }
808+
809+ fun useDeclarationParentOf (
810+ // The declaration
811+ d : IrDeclaration ,
812+ // Whether the type of entity whose parent this is can be a
813+ // top-level entity in the JVM's eyes. If so, then its parent may
814+ // be a file; otherwise, if dp is a file foo.kt, then the parent
815+ // is really the JVM class FooKt.
816+ canBeTopLevel : Boolean ,
817+ classTypeArguments : List <IrTypeArgument >? = null,
818+ inReceiverContext : Boolean = false):
819+ Label <out DbElement >? {
820+
821+ val parent = parentOf(d)
822+ if (parent is IrExternalPackageFragment ) {
823+ // This is in a file class.
824+ val fqName = getFileClassFqName(d)
825+ if (fqName == null ) {
826+ logger.error(" Can't get FqName for element in external package fragment ${d.javaClass} " )
827+ return null
828+ }
829+ return extractFileClass(fqName)
830+ }
831+ return useDeclarationParent(parent, canBeTopLevel, classTypeArguments, inReceiverContext)
832+ }
833+
834+ // Generally, useDeclarationParentOf should be used instead of
835+ // calling this directly, as this cannot handle
836+ // IrExternalPackageFragment
764837 fun useDeclarationParent (
765838 // The declaration parent according to Kotlin
766839 dp : IrDeclarationParent ,
@@ -792,8 +865,7 @@ open class KotlinUsesExtractor(
792865 }
793866 is IrFunction -> useFunction(dp)
794867 is IrExternalPackageFragment -> {
795- // TODO
796- logger.error(" Unhandled IrExternalPackageFragment" )
868+ logger.error(" Unable to handle IrExternalPackageFragment as an IrDeclarationParent" )
797869 null
798870 }
799871 else -> {
@@ -1035,7 +1107,7 @@ open class KotlinUsesExtractor(
10351107 * in.
10361108 */
10371109 fun getFunctionLabel (f : IrFunction , classTypeArgsIncludingOuterClasses : List <IrTypeArgument >? ): String? {
1038- val parentId = useDeclarationParent(f.parent , false , classTypeArgsIncludingOuterClasses, true )
1110+ val parentId = useDeclarationParentOf(f , false , classTypeArgsIncludingOuterClasses, true )
10391111 if (parentId == null ) {
10401112 logger.error(" Couldn't get parent ID for function label" )
10411113 return null
@@ -1332,7 +1404,7 @@ open class KotlinUsesExtractor(
13321404 return ids.function.cast<T >()
13331405 }
13341406 val javaFun = kotlinFunctionToJavaEquivalent(f, noReplace)
1335- val parentId = useDeclarationParent (javaFun.parent , false , classTypeArgsIncludingOuterClasses, true )
1407+ val parentId = useDeclarationParentOf (javaFun, false , classTypeArgsIncludingOuterClasses, true )
13361408 if (parentId == null ) {
13371409 logger.error(" Couldn't find parent ID for function ${f.name.asString()} " )
13381410 return null
@@ -1639,7 +1711,7 @@ open class KotlinUsesExtractor(
16391711 val overriddenParentAttributes = (declarationParent as ? IrFunction )?.let {
16401712 (this as ? KotlinFileExtractor )?.declarationStack?.findOverriddenAttributes(it)
16411713 }
1642- val parentId = parent ? : overriddenParentAttributes?.id ? : useDeclarationParent(declarationParent , false )
1714+ val parentId = parent ? : overriddenParentAttributes?.id ? : useDeclarationParentOf(vp , false )
16431715
16441716 val idxBase = overriddenParentAttributes?.valueParameters?.indexOf(vp) ? : vp.index
16451717 val idxOffset = if (declarationParent is IrFunction && declarationParent.extensionReceiverParameter != null )
@@ -1667,7 +1739,7 @@ open class KotlinUsesExtractor(
16671739 it.isConst || it.isLateinit
16681740 } ? : false
16691741
1670- fun getFieldParent (f : IrField ) =
1742+ private fun getFieldParent (f : IrField ) =
16711743 f.parentClassOrNull?.let {
16721744 if (it.isCompanion && isDirectlyExposableCompanionObjectField(f))
16731745 it.parent
@@ -1684,7 +1756,7 @@ open class KotlinUsesExtractor(
16841756 }
16851757
16861758 fun getFieldLabel (f : IrField ): String {
1687- val parentId = useDeclarationParent(getFieldParent(f) , false )
1759+ val parentId = useDeclarationParentOf(f , false )
16881760 // Distinguish backing fields of properties based on their extension receiver type;
16891761 // otherwise two extension properties declared in the same enclosing context will get
16901762 // clashing trap labels. These are always private, so we can just make up a label without
@@ -1697,7 +1769,7 @@ open class KotlinUsesExtractor(
16971769 tw.getLabelFor<DbField >(getFieldLabel(f)).also { extractFieldLaterIfExternalFileMember(f) }
16981770
16991771 fun getPropertyLabel (p : IrProperty ): String? {
1700- val parentId = useDeclarationParent(p.parent , false )
1772+ val parentId = useDeclarationParentOf(p , false )
17011773 if (parentId == null ) {
17021774 return null
17031775 } else {
@@ -1729,15 +1801,15 @@ open class KotlinUsesExtractor(
17291801 }
17301802
17311803 fun getEnumEntryLabel (ee : IrEnumEntry ): String {
1732- val parentId = useDeclarationParent (ee.parent , false )
1804+ val parentId = useDeclarationParentOf (ee, false )
17331805 return " @\" field;{$parentId };${ee.name.asString()} \" "
17341806 }
17351807
17361808 fun useEnumEntry (ee : IrEnumEntry ): Label <out DbField > =
17371809 tw.getLabelFor(getEnumEntryLabel(ee))
17381810
17391811 fun getTypeAliasLabel (ta : IrTypeAlias ): String {
1740- val parentId = useDeclarationParent (ta.parent , true )
1812+ val parentId = useDeclarationParentOf (ta, true )
17411813 return " @\" type_alias;{$parentId };${ta.name.asString()} \" "
17421814 }
17431815
0 commit comments