mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Extract generic type parameters as reference types even for primitive Kotlin types + add simplified array extraction
This commit is contained in:
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.dumpKotlinLike
|
||||
import org.jetbrains.kotlin.ir.util.packageFqName
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.render
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
@@ -170,7 +171,7 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
val pkg = file.fqName.asString()
|
||||
val pkgId = extractPackage(pkg)
|
||||
tw.writeCupackage(id, pkgId)
|
||||
file.declarations.map { extractDeclaration(it, Optional.empty()) }
|
||||
file.declarations.map { extractDeclaration(it) }
|
||||
CommentExtractor(this).extract()
|
||||
}
|
||||
|
||||
@@ -218,25 +219,33 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
return id
|
||||
}
|
||||
|
||||
fun extractDeclaration(declaration: IrDeclaration, optParentid: Optional<Label<out DbReftype>>) {
|
||||
fun extractDeclaration(declaration: IrDeclaration) {
|
||||
when (declaration) {
|
||||
is IrClass -> useClass(declaration, listOf())
|
||||
is IrFunction -> extractFunction(declaration, if (optParentid.isPresent()) optParentid.get() else fileClass)
|
||||
is IrFunction -> extractFunction(declaration)
|
||||
is IrAnonymousInitializer -> {
|
||||
// Leaving this intentionally empty. init blocks are extracted during class extraction.
|
||||
}
|
||||
is IrProperty -> extractProperty(declaration, if (optParentid.isPresent()) optParentid.get() else fileClass)
|
||||
is IrProperty -> extractProperty(declaration)
|
||||
else -> logger.warnElement(Severity.ErrorSevere, "Unrecognised IrDeclaration: " + declaration.javaClass, declaration)
|
||||
}
|
||||
}
|
||||
|
||||
fun useSimpleType(s: IrSimpleType): Label<out DbType> {
|
||||
fun useSimpleType(s: IrSimpleType, canReturnPrimitiveTypes: Boolean): Label<out DbType> {
|
||||
fun primitiveType(name: String): Label<DbPrimitive> {
|
||||
return tw.getLabelFor("@\"type;$name\"", {
|
||||
tw.writePrimitives(it, name)
|
||||
})
|
||||
}
|
||||
when {
|
||||
// temporary fix for type parameters types that would otherwise be primitive types
|
||||
!canReturnPrimitiveTypes && (s.isPrimitiveType() || s.isUnsignedType() || s.isString()) -> {
|
||||
val classifier: IrClassifierSymbol = s.classifier
|
||||
val cls: IrClass = classifier.owner as IrClass
|
||||
|
||||
return useClass(cls, s.arguments)
|
||||
}
|
||||
|
||||
s.isByte() -> return primitiveType("byte")
|
||||
s.isShort() -> return primitiveType("short")
|
||||
s.isInt() -> return primitiveType("int")
|
||||
@@ -254,10 +263,18 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
s.isChar() -> return primitiveType("char")
|
||||
s.isString() -> return primitiveType("string") // TODO: Wrong
|
||||
|
||||
s.isNullable() && s.hasQuestionMark -> return useType(s.makeNotNull()) // TODO: Wrong
|
||||
s.isNullable() && s.hasQuestionMark -> return useType(s.makeNotNull(), canReturnPrimitiveTypes) // TODO: Wrong
|
||||
|
||||
s.isNothing() -> return primitiveType("<nulltype>")
|
||||
|
||||
s.isArray() && s.arguments.isNotEmpty() -> {
|
||||
// todo: fix this, this is only a dummy implementation to let the tests pass
|
||||
val elementType = useType(s.getArrayElementType(pluginContext.irBuiltIns))
|
||||
val id = tw.getLabelFor<DbArray>("@\"array;1;{$elementType}\"")
|
||||
tw.writeArrays(id, "ARRAY", elementType, 1, elementType)
|
||||
return id
|
||||
}
|
||||
|
||||
s.classifier.owner is IrClass -> {
|
||||
val classifier: IrClassifierSymbol = s.classifier
|
||||
val cls: IrClass = classifier.owner as IrClass
|
||||
@@ -303,22 +320,29 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
}
|
||||
|
||||
fun useTypeParameter(param: IrTypeParameter): Label<out DbTypevariable> {
|
||||
return tw.getLabelFor(getTypeParameterLabel(param))
|
||||
val l = getTypeParameterLabel(param)
|
||||
return tw.getExistingLabelFor(l) ?: extractTypeParameter(param)
|
||||
}
|
||||
|
||||
private fun extractTypeParameter(tp: IrTypeParameter, optParentid: Optional<Label<out DbTypeorcallable>>) {
|
||||
val id = useTypeParameter(tp)
|
||||
private fun extractTypeParameter(tp: IrTypeParameter): Label<out DbTypevariable> {
|
||||
val id = tw.getLabelFor<DbTypevariable>(getTypeParameterLabel(tp))
|
||||
|
||||
if (!optParentid.isPresent) {
|
||||
logger.warnElement(Severity.ErrorSevere, "Couldn't find expected parent of type parameter.", tp)
|
||||
return
|
||||
val parentId: Label<out DbTypeorcallable> = when (val parent = tp.parent) {
|
||||
is IrFunction -> useFunction(parent)
|
||||
is IrClass -> useClass(parent, listOf())
|
||||
else -> {
|
||||
logger.warnElement(Severity.ErrorSevere, "Unexpected type parameter parent", tp)
|
||||
fakeLabel()
|
||||
}
|
||||
}
|
||||
|
||||
tw.writeTypeVars(id, tp.name.asString(), tp.index, 0, optParentid.get())
|
||||
tw.writeTypeVars(id, tp.name.asString(), tp.index, 0, parentId)
|
||||
val locId = tw.getLocation(tp)
|
||||
tw.writeHasLocation(id, locId)
|
||||
|
||||
// todo: add type bounds
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
private fun getClassLabel(c: IrClass, typeArgs: List<IrTypeArgument>): String {
|
||||
@@ -351,7 +375,7 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
return wildcardId
|
||||
}
|
||||
is IrTypeProjection -> {
|
||||
return useType(arg.type) as Label<out DbReftype>
|
||||
return useType(arg.type, false) as Label<out DbReftype>
|
||||
}
|
||||
else -> {
|
||||
logger.warnElement(Severity.ErrorSevere, "Unexpected type argument.", reportOn)
|
||||
@@ -441,9 +465,9 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
val unbound = useClass(c, listOf())
|
||||
tw.writeErasure(id, unbound)
|
||||
} else {
|
||||
c.typeParameters.map { extractTypeParameter(it, Optional.of(id)) }
|
||||
c.typeParameters.map { extractTypeParameter(it) }
|
||||
|
||||
c.declarations.map { extractDeclaration(it, Optional.of(id)) }
|
||||
c.declarations.map { extractDeclaration(it) }
|
||||
|
||||
extractObjectInitializerFunction(c, id)
|
||||
}
|
||||
@@ -451,9 +475,9 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
return id
|
||||
}
|
||||
|
||||
fun useType(t: IrType): Label<out DbType> {
|
||||
fun useType(t: IrType, canReturnPrimitiveTypes: Boolean = true): Label<out DbType> {
|
||||
when(t) {
|
||||
is IrSimpleType -> return useSimpleType(t)
|
||||
is IrSimpleType -> return useSimpleType(t, canReturnPrimitiveTypes)
|
||||
is IrClass -> return useClass(t, listOf())
|
||||
else -> {
|
||||
logger.warn(Severity.ErrorSevere, "Unrecognised IrType: " + t.javaClass)
|
||||
@@ -482,6 +506,13 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
return erase(owner.superTypes.get(0))
|
||||
}
|
||||
|
||||
// todo: fix this:
|
||||
if (t.makeNotNull().isArray()) {
|
||||
val elementType = t.getArrayElementType(pluginContext.irBuiltIns)
|
||||
val erasedElementType = erase(elementType)
|
||||
return (classifier as IrClassSymbol).typeWith(erasedElementType)
|
||||
}
|
||||
|
||||
if (owner is IrClass) {
|
||||
return (classifier as IrClassSymbol).typeWith()
|
||||
}
|
||||
@@ -616,20 +647,22 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
}
|
||||
}
|
||||
|
||||
fun extractFunction(f: IrFunction, parentid: Label<out DbReftype>) {
|
||||
fun extractFunction(f: IrFunction) {
|
||||
currentFunction = f
|
||||
|
||||
val locId = tw.getLocation(f)
|
||||
val signature = "TODO"
|
||||
val returnTypeId = useType(f.returnType)
|
||||
|
||||
val parentId = if (f.parent is IrClass ) useClass(f.parent as IrClass, listOf()) else fileClass
|
||||
|
||||
val id: Label<out DbCallable>
|
||||
if (f.symbol is IrConstructorSymbol) {
|
||||
id = useFunction<DbConstructor>(f)
|
||||
tw.writeConstrs(id, f.returnType.classFqName?.shortName()?.asString() ?: f.name.asString(), signature, returnTypeId, parentid, id)
|
||||
tw.writeConstrs(id, f.returnType.classFqName?.shortName()?.asString() ?: f.name.asString(), signature, returnTypeId, parentId, id)
|
||||
} else {
|
||||
id = useFunction<DbMethod>(f)
|
||||
tw.writeMethods(id, f.name.asString(), signature, returnTypeId, parentid, id)
|
||||
tw.writeMethods(id, f.name.asString(), signature, returnTypeId, parentId, id)
|
||||
|
||||
val extReceiver = f.extensionReceiverParameter
|
||||
if (extReceiver != null) {
|
||||
@@ -647,7 +680,7 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
extractValueParameter(vp, id, i)
|
||||
}
|
||||
|
||||
f.typeParameters.map { extractTypeParameter(it, Optional.of(id)) }
|
||||
f.typeParameters.map { extractTypeParameter(it) }
|
||||
|
||||
currentFunction = null
|
||||
}
|
||||
@@ -664,7 +697,7 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
return id
|
||||
}
|
||||
|
||||
fun extractProperty(p: IrProperty, parentid: Label<out DbReftype>) {
|
||||
fun extractProperty(p: IrProperty) {
|
||||
val bf = p.backingField
|
||||
if(bf == null) {
|
||||
logger.warnElement(Severity.ErrorSevere, "IrProperty without backing field", p)
|
||||
@@ -672,7 +705,8 @@ class KotlinFileExtractor(val logger: FileLogger, val tw: FileTrapWriter, val fi
|
||||
val id = useProperty(p)
|
||||
val locId = tw.getLocation(p)
|
||||
val typeId = useType(bf.type)
|
||||
tw.writeFields(id, p.name.asString(), typeId, parentid, id)
|
||||
val parentId = if (p.parent is IrClass ) useClass(p.parent as IrClass, listOf()) else fileClass
|
||||
tw.writeFields(id, p.name.asString(), typeId, parentId, id)
|
||||
tw.writeHasLocation(id, locId)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
[VALUE_NOT_IN_TYPE] predicate typeArgs(@reftype argumentid, int pos, @typeorcallable parentid): Value 55 of field argumentid is not in type @reftype. The value is however in the following types: @primitive. Appears in tuple (55,0,189)
|
||||
Relevant element: argumentid=55
|
||||
Full ID for 55: @"type;boolean"
|
||||
Relevant element: parentid=189
|
||||
Full ID for 189: @"class;kotlin.reflect.KClass;(55)". The ID may expand to @"class;kotlin.reflect.KClass;{@"type;boolean"}"
|
||||
@@ -1,31 +0,0 @@
|
||||
[VALUE_NOT_IN_TYPE] predicate typeArgs(@reftype argumentid, int pos, @typeorcallable parentid): Value 12 of field argumentid is not in type @reftype. The value is however in the following types: @primitive. Appears in tuple (12,0,135)
|
||||
Relevant element: argumentid=12
|
||||
Full ID for 12: @"type;int"
|
||||
Relevant element: parentid=135
|
||||
Full ID for 135: @"class;foo.bar.C1;(12);(12)". The ID may expand to @"class;foo.bar.C1;{@"type;int"};{@"type;int"}"
|
||||
[VALUE_NOT_IN_TYPE] predicate typeArgs(@reftype argumentid, int pos, @typeorcallable parentid): Value 12 of field argumentid is not in type @reftype. The value is however in the following types: @primitive. Appears in tuple (12,0,206)
|
||||
Relevant element: argumentid=12
|
||||
Full ID for 12: @"type;int"
|
||||
Relevant element: parentid=206
|
||||
Full ID for 206: @"class;foo.bar.C0;(12)". The ID may expand to @"class;foo.bar.C0;{@"type;int"}"
|
||||
[VALUE_NOT_IN_TYPE] predicate typeArgs(@reftype argumentid, int pos, @typeorcallable parentid): Value 12 of field argumentid is not in type @reftype. The value is however in the following types: @primitive. Appears in tuple (12,1,135)
|
||||
Relevant element: argumentid=12
|
||||
Full ID for 12: @"type;int"
|
||||
Relevant element: parentid=135
|
||||
Full ID for 135: @"class;foo.bar.C1;(12);(12)". The ID may expand to @"class;foo.bar.C1;{@"type;int"};{@"type;int"}"
|
||||
[VALUE_NOT_IN_TYPE] predicate typeArgs(@reftype argumentid, int pos, @typeorcallable parentid): Value 12 of field argumentid is not in type @reftype. The value is however in the following types: @primitive. Appears in tuple (12,1,163)
|
||||
Relevant element: argumentid=12
|
||||
Full ID for 12: @"type;int"
|
||||
Relevant element: parentid=163
|
||||
Full ID for 163: @"class;foo.bar.C1;(14);(12)". The ID may expand to @"class;foo.bar.C1;{@"type;string"};{@"type;int"}"
|
||||
[VALUE_NOT_IN_TYPE] predicate typeArgs(@reftype argumentid, int pos, @typeorcallable parentid): Value 14 of field argumentid is not in type @reftype. The value is however in the following types: @primitive. Appears in tuple (14,0,152)
|
||||
Relevant element: argumentid=14
|
||||
Full ID for 14: @"type;string"
|
||||
Relevant element: parentid=152
|
||||
Full ID for 152: @"class;foo.bar.C1;(14);(14)". The ID may expand to @"class;foo.bar.C1;{@"type;string"};{@"type;string"}"
|
||||
[VALUE_NOT_IN_TYPE] predicate typeArgs(@reftype argumentid, int pos, @typeorcallable parentid): Value 14 of field argumentid is not in type @reftype. The value is however in the following types: @primitive. Appears in tuple (14,0,163)
|
||||
Relevant element: argumentid=14
|
||||
Full ID for 14: @"type;string"
|
||||
Relevant element: parentid=163
|
||||
Full ID for 163: @"class;foo.bar.C1;(14);(12)". The ID may expand to @"class;foo.bar.C1;{@"type;string"};{@"type;int"}"
|
||||
[VALUE_NOT_IN_TYPE] predicate typeArgs(@reftype argumentid, int pos, @typeorcallable parentid): More errors, not displayed. There are 7 values of field argumentid that are not in type @reftype for a relation of size 12
|
||||
@@ -4,18 +4,18 @@ genericType
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:13:13:13 | W | 1 |
|
||||
parameterizedType
|
||||
| generics.kt:11:1:11:19 | C0 | generics.kt:11:1:11:19 | C0 | 0 | file://:0:0:0:0 | * |
|
||||
| generics.kt:11:1:11:19 | C0 | generics.kt:11:1:11:19 | C0 | 0 | file://:0:0:0:0 | int |
|
||||
| generics.kt:11:1:11:19 | C0 | generics.kt:11:1:11:19 | C0 | 0 | file://:0:0:0:0 | Int |
|
||||
| generics.kt:11:1:11:19 | C0 | generics.kt:11:1:11:19 | C0 | 0 | generics.kt:7:6:7:6 | S |
|
||||
| generics.kt:11:1:11:19 | C0 | generics.kt:11:1:11:19 | C0 | 0 | generics.kt:11:15:11:15 | V |
|
||||
| generics.kt:11:1:11:19 | C0 | generics.kt:11:1:11:19 | C0 | 0 | generics.kt:13:13:13:13 | W |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 0 | file://:0:0:0:0 | int |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 0 | file://:0:0:0:0 | string |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 0 | file://:0:0:0:0 | string |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 0 | file://:0:0:0:0 | Int |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 0 | file://:0:0:0:0 | String |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 0 | file://:0:0:0:0 | String |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 0 | generics.kt:13:10:13:10 | T |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 0 | generics.kt:15:10:15:10 | U |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 1 | file://:0:0:0:0 | int |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 1 | file://:0:0:0:0 | int |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 1 | file://:0:0:0:0 | string |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 1 | file://:0:0:0:0 | Int |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 1 | file://:0:0:0:0 | Int |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 1 | file://:0:0:0:0 | String |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 1 | generics.kt:13:13:13:13 | W |
|
||||
| generics.kt:13:1:18:1 | C1 | generics.kt:13:1:18:1 | C1 | 1 | generics.kt:15:10:15:10 | U |
|
||||
genericFunction
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import java
|
||||
|
||||
query predicate genericType(GenericType t, TypeVariable tv, int i) { t.getTypeParameter(i) = tv }
|
||||
query predicate genericType(GenericType t, TypeVariable tv, int i) {
|
||||
t.getTypeParameter(i) = tv and t.getFile().getExtension() = "kt"
|
||||
}
|
||||
|
||||
query predicate parameterizedType(ParameterizedType t, GenericType gt, int i, RefType ta) {
|
||||
t.getGenericType() = gt and
|
||||
t.getTypeArgument(i) = ta
|
||||
t.getTypeArgument(i) = ta and
|
||||
t.getFile().getExtension() = "kt"
|
||||
}
|
||||
|
||||
query predicate genericFunction(GenericCallable c, TypeVariable tv, int i) {
|
||||
c.getTypeParameter(i) = tv
|
||||
c.getTypeParameter(i) = tv and
|
||||
c.getFile().getExtension() = "kt"
|
||||
}
|
||||
|
||||
query predicate genericCall(GenericCall c, TypeVariable tv, Type t) { c.getATypeArgument(tv) = t }
|
||||
|
||||
Reference in New Issue
Block a user