@@ -2,6 +2,7 @@ package com.github.codeql
2
2
3
3
import com.github.codeql.utils.*
4
4
import com.github.codeql.utils.versions.codeQlWithHasQuestionMark
5
+ import com.github.codeql.utils.versions.getFileClassFqName
5
6
import com.github.codeql.utils.versions.getKotlinType
6
7
import com.github.codeql.utils.versions.isRawType
7
8
import com.semmle.extractor.java.OdasaOutput
@@ -71,18 +72,41 @@ open class KotlinUsesExtractor(
71
72
TypeResult (fakeKotlinType(), " " , " " )
72
73
)
73
74
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
+
74
85
fun extractFileClass (f : IrFile ): Label <out DbClassorinterface > {
75
86
val pkg = f.fqName.asString()
76
87
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 > {
77
104
val qualClassName = if (pkg.isEmpty()) jvmName else " $pkg .$jvmName "
78
105
val label = " @\" class;$qualClassName \" "
79
106
val id: Label <DbClassorinterface > = tw.getLabelFor(label) {
80
- val fileId = tw.mkFileId(f.path, false )
81
- val locId = tw.getWholeFileLocation(fileId)
82
107
val pkgId = extractPackage(pkg)
83
108
tw.writeClasses_or_interfaces(it, jvmName, pkgId, it)
84
109
tw.writeFile_class(it)
85
- tw.writeHasLocation(it, locId)
86
110
87
111
addModifiers(it, " public" , " final" )
88
112
}
@@ -250,7 +274,11 @@ open class KotlinUsesExtractor(
250
274
is IrClass -> extractExternalClassLater(parent)
251
275
is IrFunction -> extractExternalEnclosingClassLater(parent)
252
276
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} " )
254
282
}
255
283
}
256
284
@@ -293,7 +321,17 @@ open class KotlinUsesExtractor(
293
321
294
322
private fun extractFunctionLaterIfExternalFileMember (f : IrFunction ) {
295
323
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
+ }
297
335
(f as ? IrSimpleFunction )?.correspondingPropertySymbol?.let {
298
336
extractPropertyLaterIfExternalFileMember(it.owner)
299
337
// No need to extract the function specifically, as the property's
@@ -761,6 +799,41 @@ open class KotlinUsesExtractor(
761
799
}
762
800
}
763
801
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
764
837
fun useDeclarationParent (
765
838
// The declaration parent according to Kotlin
766
839
dp : IrDeclarationParent ,
@@ -792,8 +865,7 @@ open class KotlinUsesExtractor(
792
865
}
793
866
is IrFunction -> useFunction(dp)
794
867
is IrExternalPackageFragment -> {
795
- // TODO
796
- logger.error(" Unhandled IrExternalPackageFragment" )
868
+ logger.error(" Unable to handle IrExternalPackageFragment as an IrDeclarationParent" )
797
869
null
798
870
}
799
871
else -> {
@@ -1035,7 +1107,7 @@ open class KotlinUsesExtractor(
1035
1107
* in.
1036
1108
*/
1037
1109
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 )
1039
1111
if (parentId == null ) {
1040
1112
logger.error(" Couldn't get parent ID for function label" )
1041
1113
return null
@@ -1332,7 +1404,7 @@ open class KotlinUsesExtractor(
1332
1404
return ids.function.cast<T >()
1333
1405
}
1334
1406
val javaFun = kotlinFunctionToJavaEquivalent(f, noReplace)
1335
- val parentId = useDeclarationParent (javaFun.parent , false , classTypeArgsIncludingOuterClasses, true )
1407
+ val parentId = useDeclarationParentOf (javaFun, false , classTypeArgsIncludingOuterClasses, true )
1336
1408
if (parentId == null ) {
1337
1409
logger.error(" Couldn't find parent ID for function ${f.name.asString()} " )
1338
1410
return null
@@ -1639,7 +1711,7 @@ open class KotlinUsesExtractor(
1639
1711
val overriddenParentAttributes = (declarationParent as ? IrFunction )?.let {
1640
1712
(this as ? KotlinFileExtractor )?.declarationStack?.findOverriddenAttributes(it)
1641
1713
}
1642
- val parentId = parent ? : overriddenParentAttributes?.id ? : useDeclarationParent(declarationParent , false )
1714
+ val parentId = parent ? : overriddenParentAttributes?.id ? : useDeclarationParentOf(vp , false )
1643
1715
1644
1716
val idxBase = overriddenParentAttributes?.valueParameters?.indexOf(vp) ? : vp.index
1645
1717
val idxOffset = if (declarationParent is IrFunction && declarationParent.extensionReceiverParameter != null )
@@ -1667,7 +1739,7 @@ open class KotlinUsesExtractor(
1667
1739
it.isConst || it.isLateinit
1668
1740
} ? : false
1669
1741
1670
- fun getFieldParent (f : IrField ) =
1742
+ private fun getFieldParent (f : IrField ) =
1671
1743
f.parentClassOrNull?.let {
1672
1744
if (it.isCompanion && isDirectlyExposableCompanionObjectField(f))
1673
1745
it.parent
@@ -1684,7 +1756,7 @@ open class KotlinUsesExtractor(
1684
1756
}
1685
1757
1686
1758
fun getFieldLabel (f : IrField ): String {
1687
- val parentId = useDeclarationParent(getFieldParent(f) , false )
1759
+ val parentId = useDeclarationParentOf(f , false )
1688
1760
// Distinguish backing fields of properties based on their extension receiver type;
1689
1761
// otherwise two extension properties declared in the same enclosing context will get
1690
1762
// clashing trap labels. These are always private, so we can just make up a label without
@@ -1697,7 +1769,7 @@ open class KotlinUsesExtractor(
1697
1769
tw.getLabelFor<DbField >(getFieldLabel(f)).also { extractFieldLaterIfExternalFileMember(f) }
1698
1770
1699
1771
fun getPropertyLabel (p : IrProperty ): String? {
1700
- val parentId = useDeclarationParent(p.parent , false )
1772
+ val parentId = useDeclarationParentOf(p , false )
1701
1773
if (parentId == null ) {
1702
1774
return null
1703
1775
} else {
@@ -1729,15 +1801,15 @@ open class KotlinUsesExtractor(
1729
1801
}
1730
1802
1731
1803
fun getEnumEntryLabel (ee : IrEnumEntry ): String {
1732
- val parentId = useDeclarationParent (ee.parent , false )
1804
+ val parentId = useDeclarationParentOf (ee, false )
1733
1805
return " @\" field;{$parentId };${ee.name.asString()} \" "
1734
1806
}
1735
1807
1736
1808
fun useEnumEntry (ee : IrEnumEntry ): Label <out DbField > =
1737
1809
tw.getLabelFor(getEnumEntryLabel(ee))
1738
1810
1739
1811
fun getTypeAliasLabel (ta : IrTypeAlias ): String {
1740
- val parentId = useDeclarationParent (ta.parent , true )
1812
+ val parentId = useDeclarationParentOf (ta, true )
1741
1813
return " @\" type_alias;{$parentId };${ta.name.asString()} \" "
1742
1814
}
1743
1815
0 commit comments