mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
Merge pull request #9830 from smowton/smowton/fix/kotlin-annotation-class-accessors
Kotlin: annotation properties should be java.lang.Class not KClass
This commit is contained in:
@@ -628,14 +628,16 @@ open class KotlinFileExtractor(
|
||||
private fun extractValueParameter(vp: IrValueParameter, parent: Label<out DbCallable>, idx: Int, typeSubstitution: TypeSubstitution?, parentSourceDeclaration: Label<out DbCallable>, classTypeArgsIncludingOuterClasses: List<IrTypeArgument>?, extractTypeAccess: Boolean, locOverride: Label<DbLocation>? = null): TypeResults {
|
||||
with("value parameter", vp) {
|
||||
val location = locOverride ?: getLocation(vp, classTypeArgsIncludingOuterClasses)
|
||||
val maybeErasedType = (vp.parent as? IrFunction)?.let {
|
||||
val maybeAlteredType = (vp.parent as? IrFunction)?.let {
|
||||
if (overridesCollectionsMethodWithAlteredParameterTypes(it))
|
||||
eraseCollectionsMethodParameterType(vp.type, it.name.asString(), idx)
|
||||
else if ((vp.parent as? IrConstructor)?.parentClassOrNull?.kind == ClassKind.ANNOTATION_CLASS)
|
||||
kClassToJavaClass(vp.type)
|
||||
else
|
||||
null
|
||||
} ?: vp.type
|
||||
val javaType = (vp.parent as? IrFunction)?.let { getJavaCallable(it)?.let { jCallable -> getJavaValueParameterType(jCallable, idx) } }
|
||||
val typeWithWildcards = addJavaLoweringWildcards(maybeErasedType, !hasWildcardSuppressionAnnotation(vp), javaType)
|
||||
val typeWithWildcards = addJavaLoweringWildcards(maybeAlteredType, !hasWildcardSuppressionAnnotation(vp), javaType)
|
||||
val substitutedType = typeSubstitution?.let { it(typeWithWildcards, TypeContext.OTHER, pluginContext) } ?: typeWithWildcards
|
||||
val id = useValueParameter(vp, parent)
|
||||
if (extractTypeAccess) {
|
||||
@@ -734,14 +736,17 @@ open class KotlinFileExtractor(
|
||||
val initializer: IrExpressionBody?
|
||||
val lhsType: TypeResults?
|
||||
val vId: Label<out DbVariable>?
|
||||
val isAnnotationClassField: Boolean
|
||||
if (f is IrField) {
|
||||
static = f.isStatic
|
||||
initializer = f.initializer
|
||||
lhsType = useType(f.type)
|
||||
isAnnotationClassField = isAnnotationClassField(f)
|
||||
lhsType = useType(if (isAnnotationClassField) kClassToJavaClass(f.type) else f.type)
|
||||
vId = useField(f)
|
||||
} else if (f is IrEnumEntry) {
|
||||
static = true
|
||||
initializer = f.initializerExpression
|
||||
isAnnotationClassField = false
|
||||
lhsType = getEnumEntryType(f)
|
||||
if (lhsType == null) {
|
||||
return
|
||||
@@ -762,7 +767,7 @@ open class KotlinFileExtractor(
|
||||
tw.writeStmts_exprstmt(stmtId, blockAndFunctionId.first, idx++, blockAndFunctionId.second)
|
||||
tw.writeHasLocation(stmtId, declLocId)
|
||||
val assignmentId = tw.getFreshIdLabel<DbAssignexpr>()
|
||||
val type = useType(expr.type)
|
||||
val type = useType(if (isAnnotationClassField) kClassToJavaClass(expr.type) else expr.type)
|
||||
tw.writeExprs_assignexpr(assignmentId, type.javaResult.id, stmtId, 0)
|
||||
tw.writeExprsKotlinType(assignmentId, type.kotlinResult.id)
|
||||
tw.writeHasLocation(assignmentId, declLocId)
|
||||
@@ -936,7 +941,8 @@ open class KotlinFileExtractor(
|
||||
with("field", f) {
|
||||
DeclarationStackAdjuster(f).use {
|
||||
val fNameSuffix = getExtensionReceiverType(f)?.let { it.classFqName?.asString()?.replace(".", "$$") } ?: ""
|
||||
return extractField(useField(f), "${f.name.asString()}$fNameSuffix", f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal)
|
||||
val extractType = if (isAnnotationClassField(f)) kClassToJavaClass(f.type) else f.type
|
||||
return extractField(useField(f), "${f.name.asString()}$fNameSuffix", extractType, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2917,14 +2923,17 @@ open class KotlinFileExtractor(
|
||||
if (owner is IrValueParameter && owner.index == -1 && !owner.isExtensionReceiver()) {
|
||||
extractThisAccess(e, exprParent, callable)
|
||||
} else {
|
||||
extractVariableAccess(useValueDeclaration(owner), e.type, tw.getLocation(e), exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt)
|
||||
val isAnnotationClassParameter = ((owner as? IrValueParameter)?.parent as? IrConstructor)?.parentClassOrNull?.kind == ClassKind.ANNOTATION_CLASS
|
||||
val extractType = if (isAnnotationClassParameter) kClassToJavaClass(e.type) else e.type
|
||||
extractVariableAccess(useValueDeclaration(owner), extractType, tw.getLocation(e), exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt)
|
||||
}
|
||||
}
|
||||
is IrGetField -> {
|
||||
val exprParent = parent.expr(e, callable)
|
||||
val owner = tryReplaceAndroidSyntheticField(e.symbol.owner)
|
||||
val locId = tw.getLocation(e)
|
||||
extractVariableAccess(useField(owner), e.type, locId, exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt).also { id ->
|
||||
val fieldType = if (isAnnotationClassField(owner)) kClassToJavaClass(e.type) else e.type
|
||||
extractVariableAccess(useField(owner), fieldType, locId, exprParent.parent, exprParent.idx, callable, exprParent.enclosingStmt).also { id ->
|
||||
val receiver = e.receiver
|
||||
if (receiver != null) {
|
||||
extractExpressionExpr(receiver, callable, id, -1, exprParent.enclosingStmt)
|
||||
|
||||
@@ -1103,7 +1103,56 @@ open class KotlinUsesExtractor(
|
||||
return "@\"$prefix;{$parentId}.$name($paramTypeIds){$returnTypeId}${typeArgSuffix}\""
|
||||
}
|
||||
|
||||
val javaLangClass by lazy {
|
||||
val result = pluginContext.referenceClass(FqName("java.lang.Class"))?.owner
|
||||
result?.let { extractExternalClassLater(it) }
|
||||
result
|
||||
}
|
||||
|
||||
fun kClassToJavaClass(t: IrType): IrType {
|
||||
when(t) {
|
||||
is IrSimpleType -> {
|
||||
if (t.classifier == pluginContext.irBuiltIns.kClassClass) {
|
||||
javaLangClass?.let { jlc ->
|
||||
return jlc.symbol.typeWithArguments(t.arguments)
|
||||
}
|
||||
} else {
|
||||
t.classOrNull?.let { tCls ->
|
||||
if (t.isArray() || t.isNullableArray()) {
|
||||
(t.arguments.singleOrNull() as? IrTypeProjection)?.let { elementTypeArg ->
|
||||
val elementType = elementTypeArg.type
|
||||
val replacedElementType = kClassToJavaClass(elementType)
|
||||
if (replacedElementType !== elementType) {
|
||||
val newArg = makeTypeProjection(replacedElementType, elementTypeArg.variance)
|
||||
return tCls.typeWithArguments(listOf(newArg)).codeQlWithHasQuestionMark(t.isNullableArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
fun isAnnotationClassField(f: IrField) =
|
||||
f.correspondingPropertySymbol?.let {
|
||||
isAnnotationClassProperty(it)
|
||||
} ?: false
|
||||
|
||||
private fun isAnnotationClassProperty(p: IrPropertySymbol) =
|
||||
p.owner.parentClassOrNull?.kind == ClassKind.ANNOTATION_CLASS
|
||||
|
||||
fun getAdjustedReturnType(f: IrFunction) : IrType {
|
||||
// Replace annotation val accessor types as needed:
|
||||
(f as? IrSimpleFunction)?.correspondingPropertySymbol?.let {
|
||||
if (isAnnotationClassProperty(it) && f == it.owner.getter) {
|
||||
val replaced = kClassToJavaClass(f.returnType)
|
||||
if (replaced != f.returnType)
|
||||
return replaced
|
||||
}
|
||||
}
|
||||
|
||||
// The return type of `java.util.concurrent.ConcurrentHashMap<K,V>.keySet/0` is defined as `Set<K>` in the stubs inside the Android SDK.
|
||||
// This does not match the Java SDK return type: `ConcurrentHashMap.KeySetView<K,V>`, so it's adjusted here.
|
||||
// This is a deliberate change in the Android SDK: https://github.com/AndroidSDKSources/android-sdk-sources-for-api-level-31/blob/2c56b25f619575bea12f9c5520ed2259620084ac/java/util/concurrent/ConcurrentHashMap.java#L1244-L1249
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
test.kt:
|
||||
# 0| [CompilationUnit] test
|
||||
# 3| 1: [Interface] A
|
||||
# 3| 1: [Constructor] A
|
||||
#-----| 4: (Parameters)
|
||||
# 3| 0: [Parameter] c1
|
||||
# 3| 0: [TypeAccess] Class<?>
|
||||
# 3| 0: [WildcardTypeAccess] ? ...
|
||||
# 3| 1: [Parameter] c2
|
||||
# 3| 0: [TypeAccess] Class<? extends CharSequence>
|
||||
# 3| 0: [WildcardTypeAccess] ? ...
|
||||
# 3| 0: [TypeAccess] CharSequence
|
||||
# 3| 2: [Parameter] c3
|
||||
# 3| 0: [TypeAccess] Class<String>
|
||||
# 3| 0: [TypeAccess] String
|
||||
# 3| 3: [Parameter] c4
|
||||
# 3| 0: [TypeAccess] Class<?>[]
|
||||
# 3| 0: [TypeAccess] Class<?>
|
||||
# 3| 0: [WildcardTypeAccess] ? ...
|
||||
# 3| 5: [BlockStmt] { ... }
|
||||
# 3| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 3| 1: [BlockStmt] { ... }
|
||||
# 3| 0: [ExprStmt] <Expr>;
|
||||
# 3| 0: [KtInitializerAssignExpr] ...=...
|
||||
# 3| 0: [VarAccess] c1
|
||||
# 3| 1: [ExprStmt] <Expr>;
|
||||
# 3| 0: [KtInitializerAssignExpr] ...=...
|
||||
# 3| 0: [VarAccess] c2
|
||||
# 3| 2: [ExprStmt] <Expr>;
|
||||
# 3| 0: [KtInitializerAssignExpr] ...=...
|
||||
# 3| 0: [VarAccess] c3
|
||||
# 3| 3: [ExprStmt] <Expr>;
|
||||
# 3| 0: [KtInitializerAssignExpr] ...=...
|
||||
# 3| 0: [VarAccess] c4
|
||||
# 3| 2: [FieldDeclaration] Class<?> c1;
|
||||
# 3| -1: [TypeAccess] Class<?>
|
||||
# 3| 0: [WildcardTypeAccess] ? ...
|
||||
# 3| 0: [VarAccess] c1
|
||||
# 3| 3: [Method] c1
|
||||
# 3| 3: [TypeAccess] Class<?>
|
||||
# 3| 0: [WildcardTypeAccess] ? ...
|
||||
# 3| 5: [BlockStmt] { ... }
|
||||
# 3| 0: [ReturnStmt] return ...
|
||||
# 3| 0: [VarAccess] this.c1
|
||||
# 3| -1: [ThisAccess] this
|
||||
# 3| 4: [FieldDeclaration] Class<? extends CharSequence> c2;
|
||||
# 3| -1: [TypeAccess] Class<? extends CharSequence>
|
||||
# 3| 0: [WildcardTypeAccess] ? ...
|
||||
# 3| 0: [TypeAccess] CharSequence
|
||||
# 3| 0: [VarAccess] c2
|
||||
# 3| 5: [Method] c2
|
||||
# 3| 3: [TypeAccess] Class<? extends CharSequence>
|
||||
# 3| 0: [WildcardTypeAccess] ? ...
|
||||
# 3| 0: [TypeAccess] CharSequence
|
||||
# 3| 5: [BlockStmt] { ... }
|
||||
# 3| 0: [ReturnStmt] return ...
|
||||
# 3| 0: [VarAccess] this.c2
|
||||
# 3| -1: [ThisAccess] this
|
||||
# 3| 6: [FieldDeclaration] Class<String> c3;
|
||||
# 3| -1: [TypeAccess] Class<String>
|
||||
# 3| 0: [TypeAccess] String
|
||||
# 3| 0: [VarAccess] c3
|
||||
# 3| 7: [Method] c3
|
||||
# 3| 3: [TypeAccess] Class<String>
|
||||
# 3| 0: [TypeAccess] String
|
||||
# 3| 5: [BlockStmt] { ... }
|
||||
# 3| 0: [ReturnStmt] return ...
|
||||
# 3| 0: [VarAccess] this.c3
|
||||
# 3| -1: [ThisAccess] this
|
||||
# 3| 8: [FieldDeclaration] Class<?>[] c4;
|
||||
# 3| -1: [TypeAccess] Class<?>[]
|
||||
# 3| 0: [TypeAccess] Class<?>
|
||||
# 3| 0: [WildcardTypeAccess] ? ...
|
||||
# 3| 0: [VarAccess] c4
|
||||
# 3| 9: [Method] c4
|
||||
# 3| 3: [TypeAccess] Class<?>[]
|
||||
# 3| 0: [TypeAccess] Class<?>
|
||||
# 3| 0: [WildcardTypeAccess] ? ...
|
||||
# 3| 5: [BlockStmt] { ... }
|
||||
# 3| 0: [ReturnStmt] return ...
|
||||
# 3| 0: [VarAccess] this.c4
|
||||
# 3| -1: [ThisAccess] this
|
||||
@@ -0,0 +1 @@
|
||||
semmle/code/java/PrintAst.ql
|
||||
@@ -0,0 +1,37 @@
|
||||
classExprs
|
||||
| test.kt:3:20:3:36 | ...=... | Class<?> |
|
||||
| test.kt:3:20:3:36 | Class<?> | Class<?> |
|
||||
| test.kt:3:20:3:36 | Class<?> | Class<?> |
|
||||
| test.kt:3:20:3:36 | Class<?> | Class<?> |
|
||||
| test.kt:3:20:3:36 | c1 | Class<?> |
|
||||
| test.kt:3:20:3:36 | c1 | Class<?> |
|
||||
| test.kt:3:20:3:36 | this.c1 | Class<?> |
|
||||
| test.kt:3:39:3:70 | ...=... | Class<? extends CharSequence> |
|
||||
| test.kt:3:39:3:70 | Class<? extends CharSequence> | Class<? extends CharSequence> |
|
||||
| test.kt:3:39:3:70 | Class<? extends CharSequence> | Class<? extends CharSequence> |
|
||||
| test.kt:3:39:3:70 | Class<? extends CharSequence> | Class<? extends CharSequence> |
|
||||
| test.kt:3:39:3:70 | c2 | Class<? extends CharSequence> |
|
||||
| test.kt:3:39:3:70 | c2 | Class<? extends CharSequence> |
|
||||
| test.kt:3:39:3:70 | this.c2 | Class<? extends CharSequence> |
|
||||
| test.kt:3:73:3:94 | ...=... | Class<String> |
|
||||
| test.kt:3:73:3:94 | Class<String> | Class<String> |
|
||||
| test.kt:3:73:3:94 | Class<String> | Class<String> |
|
||||
| test.kt:3:73:3:94 | Class<String> | Class<String> |
|
||||
| test.kt:3:73:3:94 | c3 | Class<String> |
|
||||
| test.kt:3:73:3:94 | c3 | Class<String> |
|
||||
| test.kt:3:73:3:94 | this.c3 | Class<String> |
|
||||
| test.kt:3:97:3:120 | ...=... | Class<?>[] |
|
||||
| test.kt:3:97:3:120 | Class<?> | Class<?> |
|
||||
| test.kt:3:97:3:120 | Class<?> | Class<?> |
|
||||
| test.kt:3:97:3:120 | Class<?> | Class<?> |
|
||||
| test.kt:3:97:3:120 | Class<?>[] | Class<?>[] |
|
||||
| test.kt:3:97:3:120 | Class<?>[] | Class<?>[] |
|
||||
| test.kt:3:97:3:120 | Class<?>[] | Class<?>[] |
|
||||
| test.kt:3:97:3:120 | c4 | Class<?>[] |
|
||||
| test.kt:3:97:3:120 | c4 | Class<?>[] |
|
||||
| test.kt:3:97:3:120 | this.c4 | Class<?>[] |
|
||||
#select
|
||||
| test.kt:3:20:3:36 | c1 | Class<?> |
|
||||
| test.kt:3:39:3:70 | c2 | Class<? extends CharSequence> |
|
||||
| test.kt:3:73:3:94 | c3 | Class<String> |
|
||||
| test.kt:3:97:3:120 | c4 | Class<?>[] |
|
||||
@@ -0,0 +1,3 @@
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
annotation class A(val c1: KClass<*>, val c2: KClass<out CharSequence>, val c3: KClass<String>, val c4: Array<KClass<*>>) { }
|
||||
@@ -0,0 +1,10 @@
|
||||
import java
|
||||
|
||||
query predicate classExprs(Expr e, string tstr) {
|
||||
tstr = e.getType().toString() and
|
||||
tstr.matches("%Class%")
|
||||
}
|
||||
|
||||
from Method m
|
||||
where m.getDeclaringType().fromSource()
|
||||
select m, m.getReturnType().toString()
|
||||
Reference in New Issue
Block a user