Fix initializer field flow by extracting field finality

This commit is contained in:
Chris Smowton
2022-05-13 14:29:23 +01:00
parent eacb9f1dba
commit 81baca2c17
4 changed files with 45 additions and 5 deletions

View File

@@ -778,19 +778,22 @@ open class KotlinFileExtractor(
with("field", f) { with("field", f) {
DeclarationStackAdjuster(f).use { DeclarationStackAdjuster(f).use {
declarationStack.push(f) declarationStack.push(f)
return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f)) return extractField(useField(f), f.name.asString(), f.type, parentId, tw.getLocation(f), f.visibility, f, isExternalDeclaration(f), f.isFinal)
} }
} }
} }
private fun extractField(id: Label<out DbField>, name: String, type: IrType, parentId: Label<out DbReftype>, locId: Label<DbLocation>, visibility: DescriptorVisibility, errorElement: IrElement, isExternalDeclaration: Boolean): Label<out DbField> { private fun extractField(id: Label<out DbField>, name: String, type: IrType, parentId: Label<out DbReftype>, locId: Label<DbLocation>, visibility: DescriptorVisibility, errorElement: IrElement, isExternalDeclaration: Boolean, isFinal: Boolean): Label<out DbField> {
val t = useType(type) val t = useType(type)
tw.writeFields(id, name, t.javaResult.id, parentId, id) tw.writeFields(id, name, t.javaResult.id, parentId, id)
tw.writeFieldsKotlinType(id, t.kotlinResult.id) tw.writeFieldsKotlinType(id, t.kotlinResult.id)
tw.writeHasLocation(id, locId) tw.writeHasLocation(id, locId)
extractVisibility(errorElement, id, visibility) extractVisibility(errorElement, id, visibility)
if (isFinal) {
addModifiers(id, "final")
}
if (!isExternalDeclaration) { if (!isExternalDeclaration) {
val fieldDeclarationId = tw.getFreshIdLabel<DbFielddecl>() val fieldDeclarationId = tw.getFreshIdLabel<DbFielddecl>()
@@ -2949,12 +2952,12 @@ open class KotlinFileExtractor(
// only one of the following can be non-null: // only one of the following can be non-null:
if (dispatchReceiver != null) { if (dispatchReceiver != null) {
extractField(dispatchFieldId!!, "<dispatchReceiver>", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, false) extractField(dispatchFieldId!!, "<dispatchReceiver>", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true)
extractParameterToFieldAssignmentInConstructor("<dispatchReceiver>", dispatchReceiver.type, dispatchFieldId, 0, firstAssignmentStmtIdx) extractParameterToFieldAssignmentInConstructor("<dispatchReceiver>", dispatchReceiver.type, dispatchFieldId, 0, firstAssignmentStmtIdx)
} }
if (extensionReceiver != null) { if (extensionReceiver != null) {
extractField(extensionFieldId!!, "<extensionReceiver>", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, false) extractField(extensionFieldId!!, "<extensionReceiver>", receiverType!!, classId, locId, DescriptorVisibilities.PRIVATE, callableReferenceExpr, isExternalDeclaration = false, isFinal = true)
extractParameterToFieldAssignmentInConstructor( "<extensionReceiver>", extensionReceiver.type, extensionFieldId, 0 + extensionParameterIndex, firstAssignmentStmtIdx + extensionParameterIndex) extractParameterToFieldAssignmentInConstructor( "<extensionReceiver>", extensionReceiver.type, extensionFieldId, 0 + extensionParameterIndex, firstAssignmentStmtIdx + extensionParameterIndex)
} }
} }
@@ -4005,7 +4008,7 @@ open class KotlinFileExtractor(
// add field // add field
val fieldId = tw.getFreshIdLabel<DbField>() val fieldId = tw.getFreshIdLabel<DbField>()
extractField(fieldId, "<fn>", functionType, classId, locId, DescriptorVisibilities.PRIVATE, e, false) extractField(fieldId, "<fn>", functionType, classId, locId, DescriptorVisibilities.PRIVATE, e, isExternalDeclaration = false, isFinal = true)
// adjust constructor // adjust constructor
helper.extractParameterToFieldAssignmentInConstructor("<fn>", functionType, fieldId, 0, 1) helper.extractParameterToFieldAssignmentInConstructor("<fn>", functionType, fieldId, 0, 1)

View File

@@ -0,0 +1,4 @@
isFinalField
| test.kt:3:3:3:18 | x |
#select
| test.kt:3:3:3:18 | this.x | test.kt:6:10:6:10 | getX(...) |

View File

@@ -0,0 +1,11 @@
class Test {
val x = "Source"
fun test() {
sink(x)
}
fun sink(s: String) { }
}

View File

@@ -0,0 +1,22 @@
import java
import semmle.code.java.dataflow.DataFlow
class Config extends DataFlow::Configuration {
Config() { this = "dlkjhfgsdjgfhd2" }
override predicate isSource(DataFlow::Node n) {
n.asExpr().(CompileTimeConstantExpr).getStringValue() = "Source"
}
override predicate isSink(DataFlow::Node n) {
n.asExpr().(Argument).getCall().getCallee().getName() = "sink"
}
}
query predicate isFinalField(Field f) { exists(FieldDeclaration f2 | f = f2.getAField()) and f.isFinal() }
from DataFlow::Node source, DataFlow::Node sink
where any(Config c).hasFlow(source, sink)
select source, sink