mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Extract anonymous object creation
This commit is contained in:
@@ -372,6 +372,10 @@ open class KotlinUsesExtractor(
|
||||
}
|
||||
|
||||
fun useClassInstance(c: IrClass, typeArgs: List<IrTypeArgument>): UseClassInstanceResult {
|
||||
if (c.isAnonymousObject) {
|
||||
logger.warn(Severity.ErrorSevere, "Unexpected access to anonymous class instance")
|
||||
}
|
||||
|
||||
// TODO: only substitute in class and function signatures
|
||||
// because within function bodies we can get things like Unit.INSTANCE
|
||||
// and List.asIterable (an extension, i.e. static, method)
|
||||
@@ -432,7 +436,22 @@ open class KotlinUsesExtractor(
|
||||
classLabelResult.shortName)
|
||||
}
|
||||
|
||||
open fun useAnonymousClass(c: IrClass): TypeResults {
|
||||
throw Exception("Anonymous classes can only be accessed through source file extraction")
|
||||
}
|
||||
|
||||
fun useSimpleTypeClass(c: IrClass, args: List<IrTypeArgument>, hasQuestionMark: Boolean): TypeResults {
|
||||
if (c.isAnonymousObject) {
|
||||
if (args.isNotEmpty()) {
|
||||
logger.warn(Severity.ErrorHigh, "Anonymous class with unexpected type arguments")
|
||||
}
|
||||
if (hasQuestionMark) {
|
||||
logger.warn(Severity.ErrorHigh, "Unexpected nullable anonymous class")
|
||||
}
|
||||
|
||||
return useAnonymousClass(c)
|
||||
}
|
||||
|
||||
val classInstanceResult = useClassInstance(c, args)
|
||||
val javaClassId = classInstanceResult.typeResult.id
|
||||
val kotlinQualClassName = getUnquotedClassLabel(c, args).classLabel
|
||||
@@ -785,7 +804,12 @@ class X {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun getClassLabel(c: IrClass, typeArgs: List<IrTypeArgument>): ClassLabelResults {
|
||||
if (c.isAnonymousObject) {
|
||||
logger.warn(Severity.ErrorSevere, "Label generation should not be requested for an anonymous class")
|
||||
}
|
||||
|
||||
val unquotedLabel = getUnquotedClassLabel(c, typeArgs)
|
||||
return ClassLabelResults(
|
||||
"@\"class;${unquotedLabel.classLabel}\"",
|
||||
@@ -793,6 +817,11 @@ class X {
|
||||
}
|
||||
|
||||
fun useClassSource(c: IrClass): Label<out DbClassorinterface> {
|
||||
if (c.isAnonymousObject) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return useAnonymousClass(c).javaResult.id as Label<DbClass>
|
||||
}
|
||||
|
||||
// For source classes, the label doesn't include and type arguments
|
||||
val classId = getClassLabel(c, listOf())
|
||||
return tw.getLabelFor(classId.classLabel)
|
||||
@@ -1052,8 +1081,28 @@ open class KotlinFileExtractor(
|
||||
return id
|
||||
}
|
||||
|
||||
private val anonymousTypeMap: MutableMap<IrClass, TypeResults> = mutableMapOf()
|
||||
|
||||
override fun useAnonymousClass(c: IrClass): TypeResults {
|
||||
var res = anonymousTypeMap[c]
|
||||
if (res == null) {
|
||||
val javaResult = TypeResult(tw.getFreshIdLabel<DbClass>(), "", "")
|
||||
val kotlinResult = TypeResult(tw.getFreshIdLabel<DbKt_notnull_type>() , "", "")
|
||||
tw.writeKt_notnull_types(kotlinResult.id, javaResult.id)
|
||||
res = TypeResults(javaResult, kotlinResult)
|
||||
anonymousTypeMap[c] = res
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
fun extractClassSource(c: IrClass): Label<out DbClassorinterface> {
|
||||
val id = useClassSource(c)
|
||||
val id = if (c.isAnonymousObject) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
useAnonymousClass(c).javaResult.id as Label<out DbClass>
|
||||
} else {
|
||||
useClassSource(c)
|
||||
}
|
||||
val pkg = c.packageFqName?.asString() ?: ""
|
||||
val cls = c.name.asString()
|
||||
val pkgId = extractPackage(pkg)
|
||||
@@ -1074,24 +1123,36 @@ open class KotlinFileExtractor(
|
||||
val locId = tw.getLocation(c)
|
||||
tw.writeHasLocation(id, locId)
|
||||
|
||||
val parent = c.parent
|
||||
if (parent is IrClass) {
|
||||
val parentId = useClassInstance(parent, listOf()).typeResult.id
|
||||
tw.writeEnclInReftype(id, parentId)
|
||||
if(c.isCompanion) {
|
||||
// If we are a companion then our parent has a
|
||||
// public static final ParentClass$CompanionObjectClass CompanionObjectName;
|
||||
// that we need to fabricate here
|
||||
val instance = useCompanionObjectClassInstance(c)
|
||||
if(instance != null) {
|
||||
val type = useSimpleTypeClass(c, emptyList(), false)
|
||||
tw.writeFields(instance.id, instance.name, type.javaResult.id, type.kotlinResult.id, id, instance.id)
|
||||
tw.writeHasLocation(instance.id, locId)
|
||||
addModifiers(instance.id, "public", "static", "final")
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
tw.writeClass_companion_object(parentId as Label<DbClass>, instance.id, id as Label<DbClass>)
|
||||
var parent: IrDeclarationParent? = c.parent
|
||||
while (parent != null) {
|
||||
if (parent is IrClass) {
|
||||
val parentId =
|
||||
if (parent.isAnonymousObject) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
useAnonymousClass(c).javaResult.id as Label<out DbClass>
|
||||
} else {
|
||||
useClassInstance(parent, listOf()).typeResult.id
|
||||
}
|
||||
tw.writeEnclInReftype(id, parentId)
|
||||
if(c.isCompanion) {
|
||||
// If we are a companion then our parent has a
|
||||
// public static final ParentClass$CompanionObjectClass CompanionObjectName;
|
||||
// that we need to fabricate here
|
||||
val instance = useCompanionObjectClassInstance(c)
|
||||
if(instance != null) {
|
||||
val type = useSimpleTypeClass(c, emptyList(), false)
|
||||
tw.writeFields(instance.id, instance.name, type.javaResult.id, type.kotlinResult.id, id, instance.id)
|
||||
tw.writeHasLocation(instance.id, locId)
|
||||
addModifiers(instance.id, "public", "static", "final")
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
tw.writeClass_companion_object(parentId as Label<DbClass>, instance.id, id as Label<DbClass>)
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
parent = (parent as? IrDeclaration)?.parent
|
||||
}
|
||||
|
||||
c.typeParameters.map { extractTypeParameter(it) }
|
||||
@@ -1390,6 +1451,13 @@ open class KotlinFileExtractor(
|
||||
is IrVariable -> {
|
||||
extractVariable(s, callable, parent, idx)
|
||||
}
|
||||
is IrClass -> {
|
||||
if (s.isAnonymousObject) {
|
||||
logger.info("Skipping extracting anonymous object class. It will be extracted later where it's instantiated.")
|
||||
} else {
|
||||
logger.warnElement(Severity.ErrorSevere, "Found non anonymous IrClass as IrStatement: " + s.javaClass, s)
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
logger.warnElement(Severity.ErrorSevere, "Unrecognised IrStatement: " + s.javaClass, s)
|
||||
}
|
||||
@@ -1706,7 +1774,22 @@ open class KotlinFileExtractor(
|
||||
callable: Label<out DbCallable>
|
||||
) {
|
||||
val id = tw.getFreshIdLabel<DbNewexpr>()
|
||||
val type = useType(e.type)
|
||||
val type: TypeResults
|
||||
val isAnonymous = ((e.type as? IrSimpleType)?.classifier?.owner as? IrClass)?.isAnonymousObject ?: false
|
||||
if (isAnonymous) {
|
||||
if (e.typeArgumentsCount > 0) {
|
||||
logger.warn("Unexpected type arguments for anonymous class constructor call")
|
||||
}
|
||||
|
||||
val c = (e.type as IrSimpleType).classifier.owner as IrClass
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val classId = extractClassSource(c) as Label<out DbClass>
|
||||
tw.writeIsAnonymClass(classId, id)
|
||||
|
||||
type = useAnonymousClass(c)
|
||||
} else {
|
||||
type = useType(e.type)
|
||||
}
|
||||
val locId = tw.getLocation(e)
|
||||
val methodId = useFunction<DbConstructor>(e.symbol.owner)
|
||||
tw.writeExprs_newexpr(id, type.javaResult.id, type.kotlinResult.id, parent, idx)
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
| classes.kt:66:20:66:54 | (no string representation) | classes.kt:66:20:66:54 | new <no name provided>(...) |
|
||||
| classes.kt:68:20:68:74 | (no string representation) | classes.kt:68:20:68:74 | new <no name provided>(...) |
|
||||
| classes.kt:72:16:77:10 | (no string representation) | classes.kt:72:16:77:10 | new <no name provided>(...) |
|
||||
| classes.kt:75:24:75:33 | (no string representation) | classes.kt:75:24:75:33 | new <no name provided>(...) |
|
||||
| classes.kt:81:16:81:38 | (no string representation) | classes.kt:81:16:81:38 | new <no name provided>(...) |
|
||||
| classes.kt:85:16:85:25 | (no string representation) | classes.kt:85:16:85:25 | new <no name provided>(...) |
|
||||
| classes.kt:89:16:89:44 | (no string representation) | classes.kt:89:16:89:44 | new <no name provided>(...) |
|
||||
@@ -0,0 +1,6 @@
|
||||
import java
|
||||
|
||||
from AnonymousClass c
|
||||
where c.fromSource()
|
||||
select c, c.getClassInstanceExpr()
|
||||
|
||||
@@ -8,3 +8,11 @@
|
||||
| classes.kt:34:1:47:1 | ClassSeven | ClassSeven |
|
||||
| classes.kt:49:1:51:1 | Direction | Direction |
|
||||
| classes.kt:53:1:57:1 | Color | Color |
|
||||
| classes.kt:63:1:91:1 | Class1 | Class1 |
|
||||
| classes.kt:66:20:66:54 | (no string representation) | <anonymous class> |
|
||||
| classes.kt:68:20:68:74 | (no string representation) | <anonymous class> |
|
||||
| classes.kt:72:16:77:10 | (no string representation) | <anonymous class> |
|
||||
| classes.kt:75:24:75:33 | (no string representation) | <anonymous class> |
|
||||
| classes.kt:81:16:81:38 | (no string representation) | <anonymous class> |
|
||||
| classes.kt:85:16:85:25 | (no string representation) | <anonymous class> |
|
||||
| classes.kt:89:16:89:44 | (no string representation) | <anonymous class> |
|
||||
|
||||
@@ -55,3 +55,37 @@ enum class Color(val rgb: Int) {
|
||||
GREEN(0x00FF00),
|
||||
BLUE(0x0000FF)
|
||||
}
|
||||
|
||||
interface Interface1 {}
|
||||
interface Interface2 {}
|
||||
interface Interface3<T> {}
|
||||
|
||||
class Class1 {
|
||||
private fun getObject1(b: Boolean) : Any {
|
||||
if (b)
|
||||
return object : Interface1, Interface2 { }
|
||||
else
|
||||
return object : Interface1, Interface2, Interface3<String> { }
|
||||
}
|
||||
|
||||
private fun getObject2() : Interface1 {
|
||||
return object : Interface1, Interface2 {
|
||||
val x = 1
|
||||
fun foo(): Any {
|
||||
return object { }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getObject3() : Any {
|
||||
return object : Interface1 { }
|
||||
}
|
||||
|
||||
private fun getObject4() : Any {
|
||||
return object { }
|
||||
}
|
||||
|
||||
private fun getObject5() : Any {
|
||||
return object : Interface3<Int?> { }
|
||||
}
|
||||
}
|
||||
@@ -8,3 +8,11 @@ superCall
|
||||
| classes.kt:17:18:17:28 | super(...) |
|
||||
| classes.kt:28:19:28:29 | super(...) |
|
||||
| classes.kt:35:27:35:27 | super(...) |
|
||||
| classes.kt:63:1:91:1 | super(...) |
|
||||
| classes.kt:66:20:66:54 | super(...) |
|
||||
| classes.kt:68:20:68:74 | super(...) |
|
||||
| classes.kt:72:16:77:10 | super(...) |
|
||||
| classes.kt:75:24:75:33 | super(...) |
|
||||
| classes.kt:81:16:81:38 | super(...) |
|
||||
| classes.kt:85:16:85:25 | super(...) |
|
||||
| classes.kt:89:16:89:44 | super(...) |
|
||||
|
||||
@@ -10,6 +10,17 @@ initBlocks
|
||||
| classes.kt:34:1:47:1 | <obinit> |
|
||||
| classes.kt:49:1:51:1 | <obinit> |
|
||||
| classes.kt:53:1:57:1 | <obinit> |
|
||||
| classes.kt:59:1:59:23 | <obinit> |
|
||||
| classes.kt:60:1:60:23 | <obinit> |
|
||||
| classes.kt:61:1:61:26 | <obinit> |
|
||||
| classes.kt:63:1:91:1 | <obinit> |
|
||||
| classes.kt:66:20:66:54 | <obinit> |
|
||||
| classes.kt:68:20:68:74 | <obinit> |
|
||||
| classes.kt:72:16:77:10 | <obinit> |
|
||||
| classes.kt:75:24:75:33 | <obinit> |
|
||||
| classes.kt:81:16:81:38 | <obinit> |
|
||||
| classes.kt:85:16:85:25 | <obinit> |
|
||||
| classes.kt:89:16:89:44 | <obinit> |
|
||||
initCall
|
||||
| classes.kt:2:1:2:18 | <obinit>(...) |
|
||||
| classes.kt:4:1:6:1 | <obinit>(...) |
|
||||
@@ -20,6 +31,14 @@ initCall
|
||||
| classes.kt:35:5:37:5 | <obinit>(...) |
|
||||
| classes.kt:49:1:51:1 | <obinit>(...) |
|
||||
| classes.kt:53:1:57:1 | <obinit>(...) |
|
||||
| classes.kt:63:1:91:1 | <obinit>(...) |
|
||||
| classes.kt:66:20:66:54 | <obinit>(...) |
|
||||
| classes.kt:68:20:68:74 | <obinit>(...) |
|
||||
| classes.kt:72:16:77:10 | <obinit>(...) |
|
||||
| classes.kt:75:24:75:33 | <obinit>(...) |
|
||||
| classes.kt:81:16:81:38 | <obinit>(...) |
|
||||
| classes.kt:85:16:85:25 | <obinit>(...) |
|
||||
| classes.kt:89:16:89:44 | <obinit>(...) |
|
||||
initExpressions
|
||||
| classes.kt:4:17:4:28 | ...=... | 0 |
|
||||
| classes.kt:5:5:5:18 | ...=... | 1 |
|
||||
@@ -27,3 +46,4 @@ initExpressions
|
||||
| classes.kt:42:5:42:18 | ...=... | 1 |
|
||||
| classes.kt:45:9:45:18 | f(...) | 2 |
|
||||
| classes.kt:53:18:53:29 | ...=... | 0 |
|
||||
| classes.kt:73:13:73:21 | ...=... | 0 |
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
| classes.kt:20:1:22:1 | IF1 |
|
||||
| classes.kt:24:1:26:1 | IF2 |
|
||||
| classes.kt:59:1:59:23 | Interface1 |
|
||||
| classes.kt:60:1:60:23 | Interface2 |
|
||||
| classes.kt:61:1:61:26 | Interface3 |
|
||||
|
||||
@@ -9,3 +9,15 @@
|
||||
| classes.kt:34:1:47:1 | ClassSeven | Object | Object.class | 0 | 0 | 0 | 0 |
|
||||
| classes.kt:49:1:51:1 | Direction | Enum<Direction> | Enum.class | 0 | 0 | 0 | 0 |
|
||||
| classes.kt:53:1:57:1 | Color | Enum<Color> | Enum.class | 0 | 0 | 0 | 0 |
|
||||
| classes.kt:63:1:91:1 | Class1 | Object | Object.class | 0 | 0 | 0 | 0 |
|
||||
| classes.kt:66:20:66:54 | (no string representation) | Interface1 | classes.kt | 59 | 1 | 59 | 23 |
|
||||
| classes.kt:66:20:66:54 | (no string representation) | Interface2 | classes.kt | 60 | 1 | 60 | 23 |
|
||||
| classes.kt:68:20:68:74 | (no string representation) | Interface1 | classes.kt | 59 | 1 | 59 | 23 |
|
||||
| classes.kt:68:20:68:74 | (no string representation) | Interface2 | classes.kt | 60 | 1 | 60 | 23 |
|
||||
| classes.kt:68:20:68:74 | (no string representation) | Interface3<String> | classes.kt | 61 | 1 | 61 | 26 |
|
||||
| classes.kt:72:16:77:10 | (no string representation) | Interface1 | classes.kt | 59 | 1 | 59 | 23 |
|
||||
| classes.kt:72:16:77:10 | (no string representation) | Interface2 | classes.kt | 60 | 1 | 60 | 23 |
|
||||
| classes.kt:75:24:75:33 | (no string representation) | Object | Object.class | 0 | 0 | 0 | 0 |
|
||||
| classes.kt:81:16:81:38 | (no string representation) | Interface1 | classes.kt | 59 | 1 | 59 | 23 |
|
||||
| classes.kt:85:16:85:25 | (no string representation) | Object | Object.class | 0 | 0 | 0 | 0 |
|
||||
| classes.kt:89:16:89:44 | (no string representation) | Interface3<Integer> | classes.kt | 61 | 1 | 61 | 26 |
|
||||
|
||||
@@ -16,3 +16,4 @@
|
||||
| exprs.kt:54:12:54:23 | ... > ... | exprs.kt:54:12:54:19 | variable | exprs.kt:54:23:54:23 | 0 |
|
||||
| exprs.kt:58:12:58:20 | ... + ... | exprs.kt:58:12:58:14 | 123 | exprs.kt:58:18:58:20 | 456 |
|
||||
| exprs.kt:84:8:84:16 | ... != ... | exprs.kt:84:8:84:8 | r | exprs.kt:84:13:84:16 | null |
|
||||
| exprs.kt:113:31:113:37 | ... + ... | exprs.kt:113:31:113:32 | <get-a1>(...) | exprs.kt:113:36:113:37 | a2 |
|
||||
|
||||
@@ -223,6 +223,24 @@
|
||||
| exprs.kt:102:27:102:31 | SOUTH | exprs.kt:101:1:104:1 | enums | VarAccess |
|
||||
| exprs.kt:103:5:103:27 | green | exprs.kt:101:1:104:1 | enums | LocalVariableDeclExpr |
|
||||
| exprs.kt:103:23:103:27 | GREEN | exprs.kt:101:1:104:1 | enums | VarAccess |
|
||||
| exprs.kt:108:1:116:1 | <obinit>(...) | exprs.kt:108:1:116:1 | Class1 | MethodAccess |
|
||||
| exprs.kt:109:5:109:14 | ...=... | exprs.kt:108:1:116:1 | <obinit> | AssignExpr |
|
||||
| exprs.kt:109:5:109:14 | a1 | exprs.kt:108:1:116:1 | <obinit> | VarAccess |
|
||||
| exprs.kt:109:5:109:14 | a1 | exprs.kt:109:5:109:14 | <get-a1> | VarAccess |
|
||||
| exprs.kt:109:14:109:14 | 1 | exprs.kt:108:1:116:1 | <obinit> | IntegerLiteral |
|
||||
| exprs.kt:111:9:111:18 | a2 | exprs.kt:110:13:115:5 | getObject | LocalVariableDeclExpr |
|
||||
| exprs.kt:111:18:111:18 | 2 | exprs.kt:110:13:115:5 | getObject | IntegerLiteral |
|
||||
| exprs.kt:112:16:114:9 | <Stmt> | exprs.kt:110:13:115:5 | getObject | StmtExpr |
|
||||
| exprs.kt:112:16:114:9 | <obinit>(...) | exprs.kt:112:16:114:9 | <no name provided> | MethodAccess |
|
||||
| exprs.kt:112:16:114:9 | new <no name provided>(...) | exprs.kt:110:13:115:5 | getObject | ClassInstanceExpr |
|
||||
| exprs.kt:113:13:113:49 | ...=... | exprs.kt:112:16:114:9 | <obinit> | AssignExpr |
|
||||
| exprs.kt:113:13:113:49 | a3 | exprs.kt:112:16:114:9 | <obinit> | VarAccess |
|
||||
| exprs.kt:113:13:113:49 | a3 | exprs.kt:113:13:113:49 | <get-a3> | VarAccess |
|
||||
| exprs.kt:113:31:113:32 | <get-a1>(...) | exprs.kt:112:16:114:9 | <obinit> | MethodAccess |
|
||||
| exprs.kt:113:31:113:32 | this | exprs.kt:112:16:114:9 | <obinit> | ThisAccess |
|
||||
| exprs.kt:113:31:113:37 | ... + ... | exprs.kt:112:16:114:9 | <obinit> | AddExpr |
|
||||
| exprs.kt:113:36:113:37 | a2 | exprs.kt:112:16:114:9 | <obinit> | VarAccess |
|
||||
| exprs.kt:113:40:113:49 | toString(...) | exprs.kt:112:16:114:9 | <obinit> | MethodAccess |
|
||||
| file://:0:0:0:0 | Color | exprs.kt:95:6:99:1 | Color | TypeAccess |
|
||||
| file://:0:0:0:0 | Direction | exprs.kt:91:6:93:1 | Direction | TypeAccess |
|
||||
| file://:0:0:0:0 | height | exprs.kt:82:1:89:1 | foo | VarAccess |
|
||||
|
||||
@@ -102,3 +102,15 @@ fun enums() {
|
||||
val south = Direction.SOUTH
|
||||
val green = Color.GREEN
|
||||
}
|
||||
|
||||
interface Interface1 {}
|
||||
|
||||
class Class1 {
|
||||
val a1 = 1
|
||||
private fun getObject() : Any {
|
||||
val a2 = 2
|
||||
return object : Interface1 {
|
||||
val a3: String = (a1 + a2).toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user