Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e6e5623

Browse files
committed
Kotlin: Handle properties better
1 parent 44bf35e commit e6e5623

8 files changed

Lines changed: 232 additions & 17 deletions

File tree

java/kotlin-extractor/src/main/kotlin/KotlinExtractorExtension.kt

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -937,18 +937,30 @@ class X {
937937
return id
938938
}
939939

940-
fun getPropertyLabel(p: IrProperty) : String {
940+
fun getFieldLabel(p: IrField) : String {
941941
val parentId = useDeclarationParent(p.parent)
942942
val label = "@\"field;{$parentId};${p.name.asString()}\""
943943
return label
944944
}
945945

946-
fun useProperty(p: IrProperty): Label<out DbField> {
947-
var label = getPropertyLabel(p)
946+
fun useField(p: IrField): Label<out DbField> {
947+
var label = getFieldLabel(p)
948948
val id: Label<DbField> = tw.getLabelFor(label)
949949
return id
950950
}
951951

952+
fun getPropertyLabel(p: IrProperty) : String {
953+
val parentId = useDeclarationParent(p.parent)
954+
val label = "@\"property;{$parentId};${p.name.asString()}\""
955+
return label
956+
}
957+
958+
fun useProperty(p: IrProperty): Label<out DbKt_property> {
959+
var label = getPropertyLabel(p)
960+
val id: Label<DbKt_property> = tw.getLabelFor(label)
961+
return id
962+
}
963+
952964
private fun getEnumEntryLabel(ee: IrEnumEntry) : String {
953965
val parentId = useDeclarationParent(ee.parent)
954966
val label = "@\"field;{$parentId};${ee.name.asString()}\""
@@ -1216,12 +1228,15 @@ open class KotlinFileExtractor(
12161228
tw.writeExprs_assignexpr(assignmentId, type.javaResult.id, type.kotlinResult.id, stmtId, 0)
12171229
tw.writeHasLocation(assignmentId, declLocId)
12181230

1231+
/*
1232+
TODO
12191233
val lhsId = tw.getFreshIdLabel<DbVaraccess>()
12201234
val lhsType = useType(backingField.type)
12211235
tw.writeExprs_varaccess(lhsId, lhsType.javaResult.id, lhsType.kotlinResult.id, assignmentId, 0)
12221236
tw.writeHasLocation(lhsId, declLocId)
12231237
val vId = useProperty(decl) // todo: fix this. We should be assigning the field, and not the property
12241238
tw.writeVariableBinding(lhsId, vId)
1239+
*/
12251240

12261241
extractExpressionExpr(initializer.expression, obinitId, assignmentId, 1)
12271242
}
@@ -1239,7 +1254,7 @@ open class KotlinFileExtractor(
12391254
}
12401255
}
12411256

1242-
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>) {
1257+
fun extractFunction(f: IrFunction, parentId: Label<out DbReftype>): Label<out DbCallable> {
12431258
currentFunction = f
12441259

12451260
f.typeParameters.map { extractTypeParameter(it) }
@@ -1274,24 +1289,57 @@ open class KotlinFileExtractor(
12741289
}
12751290

12761291
currentFunction = null
1292+
return id
1293+
}
1294+
1295+
fun extractField(f: IrField, parentId: Label<out DbReftype>): Label<out DbField> {
1296+
val id = useField(f)
1297+
val locId = tw.getLocation(f)
1298+
val type = useType(f.type)
1299+
tw.writeFields(id, f.name.asString(), type.javaResult.id, type.kotlinResult.id, parentId, id)
1300+
tw.writeHasLocation(id, locId)
1301+
return id
12771302
}
12781303

12791304
fun extractProperty(p: IrProperty, parentId: Label<out DbReftype>) {
1305+
val id = useProperty(p)
1306+
val locId = tw.getLocation(p)
1307+
tw.writeKtProperties(id, p.name.asString())
1308+
tw.writeHasLocation(id, locId)
1309+
12801310
val bf = p.backingField
1281-
if(bf == null) {
1282-
logger.warnElement(Severity.ErrorSevere, "IrProperty without backing field", p)
1311+
val getter = p.getter
1312+
val setter = p.setter
1313+
1314+
if(getter != null) {
1315+
@Suppress("UNCHECKED_CAST")
1316+
val getterId = extractFunction(getter, parentId) as Label<out DbMethod>
1317+
tw.writeKtPropertyGetters(id, getterId)
12831318
} else {
1284-
val id = useProperty(p)
1285-
val locId = tw.getLocation(p)
1286-
val type = useType(bf.type)
1287-
tw.writeFields(id, p.name.asString(), type.javaResult.id, type.kotlinResult.id, parentId, id)
1288-
tw.writeHasLocation(id, locId)
1319+
logger.warnElement(Severity.ErrorSevere, "IrProperty without a getter", p)
1320+
}
1321+
1322+
if(setter != null) {
1323+
if(!p.isVar) {
1324+
logger.warnElement(Severity.ErrorSevere, "!isVar property with a setter", p)
1325+
}
1326+
@Suppress("UNCHECKED_CAST")
1327+
val setterId = extractFunction(setter, parentId) as Label<out DbMethod>
1328+
tw.writeKtPropertySetters(id, setterId)
1329+
} else {
1330+
if(p.isVar) {
1331+
logger.warnElement(Severity.ErrorSevere, "isVar property without a setter", p)
1332+
}
1333+
}
1334+
1335+
if(bf != null) {
1336+
val fieldId = extractField(bf, parentId)
1337+
tw.writeKtPropertyBackingFields(id, fieldId)
12891338
}
12901339
}
12911340

12921341
fun extractEnumEntry(ee: IrEnumEntry, parentId: Label<out DbReftype>) {
12931342
val id = useEnumEntry(ee)
1294-
val locId = tw.getLocation(ee)
12951343
val parent = ee.parent
12961344
if(parent !is IrClass) {
12971345
logger.warnElement(Severity.ErrorSevere, "Enum entry with unexpected parent: " + parent.javaClass, ee)
@@ -1300,6 +1348,7 @@ open class KotlinFileExtractor(
13001348
} else {
13011349
val type = useSimpleTypeClass(parent, emptyList(), false)
13021350
tw.writeFields(id, ee.name.asString(), type.javaResult.id, type.kotlinResult.id, parentId, id)
1351+
val locId = tw.getLocation(ee)
13031352
tw.writeHasLocation(id, locId)
13041353
}
13051354
}

java/kotlin-extractor/src/main/kotlin/utils/Logger.kt

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ open class Logger(val logCounter: LogCounter, open val tw: TrapWriter) {
6767
fun trace(msg: String, exn: Exception) {
6868
trace(msg + " // " + exn)
6969
}
70-
fun warn(severity: Severity, msg: String, locationString: String? = null, locationId: Label<DbLocation> = tw.unknownLocation) {
70+
fun warn(severity: Severity, msg: String, locationString: String? = null, mkLocationId: () -> Label<DbLocation> = { tw.unknownLocation }) {
7171
val warningLoc = getWarningLocation()
7272
val warningLocStr = if(warningLoc == null) "<unknown location>" else warningLoc
7373
val suffix =
@@ -84,6 +84,8 @@ open class Logger(val logCounter: LogCounter, open val tw: TrapWriter) {
8484
}
8585
}
8686
val ts = timestamp()
87+
// We don't actually make the location until after the `return` above
88+
val locationId = mkLocationId()
8789
tw.writeDiagnostics(StarLabel(), "CodeQL Kotlin extractor", severity.sev, "", msg, "$ts $msg\n$suffix", locationId)
8890
val locStr = if (locationString == null) "" else "At " + locationString + ": "
8991
print("$ts Warning($warningLocStr): $locStr$msg\n$suffix")
@@ -118,7 +120,7 @@ class FileLogger(logCounter: LogCounter, override val tw: FileTrapWriter): Logge
118120

119121
fun warnElement(severity: Severity, msg: String, element: IrElement) {
120122
val locationString = tw.getLocationString(element)
121-
val locationId = tw.getLocation(element)
122-
warn(severity, msg, locationString, locationId)
123+
val mkLocationId = { tw.getLocation(element) }
124+
warn(severity, msg, locationString, mkLocationId)
123125
}
124126
}

java/ql/lib/config/semmlecode.dbscheme

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,8 @@ javadocText(
948948

949949
/** A program element that has a name. */
950950
@element = @file | @package | @primitive | @class | @interface | @method | @constructor | @modifier | @param | @exception | @field |
951-
@annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias;
951+
@annotation | @boundedtype | @array | @localvar | @expr | @stmt | @import | @fielddecl | @kt_type | @kt_type_alias |
952+
@kt_property;
952953

953954
@modifiable = @member_modifiable| @param | @localvar ;
954955

@@ -960,7 +961,7 @@ javadocText(
960961
@locatable = @file | @class | @interface | @fielddecl | @field | @constructor | @method | @param | @exception
961962
| @boundedtype | @typebound | @array | @primitive
962963
| @import | @stmt | @expr | @whenbranch | @localvar | @javadoc | @javadocTag | @javadocText
963-
| @xmllocatable | @ktcomment | @kt_type_alias;
964+
| @xmllocatable | @ktcomment | @kt_type_alias | @kt_property;
964965

965966
@top = @element | @locatable | @folder;
966967

@@ -1108,3 +1109,23 @@ ktExtensionFunctions(
11081109
int typeid: @type ref,
11091110
int kttypeid: @kt_type ref
11101111
)
1112+
1113+
ktProperties(
1114+
unique int id: @kt_property,
1115+
string nodeName: string ref
1116+
)
1117+
1118+
ktPropertyGetters(
1119+
unique int id: @kt_property ref,
1120+
int getter: @method ref
1121+
)
1122+
1123+
ktPropertySetters(
1124+
unique int id: @kt_property ref,
1125+
int setter: @method ref
1126+
)
1127+
1128+
ktPropertyBackingFields(
1129+
unique int id: @kt_property ref,
1130+
int backingField: @field ref
1131+
)

java/ql/lib/semmle/code/Location.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ predicate hasName(Element e, string name) {
4545
modifiers(e, name)
4646
or
4747
kt_type_alias(e, name, _)
48+
or
49+
ktProperties(e, name)
4850
}
4951

5052
/**

java/ql/lib/semmle/code/java/Member.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,20 @@ class InstanceField extends Field {
686686
InstanceField() { not this.isStatic() }
687687
}
688688

689+
/** A Kotlin property. */
690+
class Property extends Element, @kt_property {
691+
/** Gets the getter method for this property, if any. */
692+
Method getGetter() { ktPropertyGetters(this, result) }
693+
694+
/** Gets the setter method for this property, if any. */
695+
Method getSetter() { ktPropertySetters(this, result) }
696+
697+
/** Gets the backing field for this property, if any. */
698+
Field getBackingField() { ktPropertyBackingFields(this, result) }
699+
700+
override string getAPrimaryQlClass() { result = "Property" }
701+
}
702+
689703
/** A Kotlin extension function. */
690704
class ExtensionMethod extends Method {
691705
Type extendedType;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
| properties.kt:2:27:2:50 | constructorProp | properties.kt:2:27:2:50 | <get-constructorProp> | file://:0:0:0:0 | <none> | properties.kt:2:27:2:50 | constructorProp |
2+
| properties.kt:2:53:2:83 | mutableConstructorProp | properties.kt:2:53:2:83 | <get-mutableConstructorProp> | properties.kt:2:53:2:83 | <set-mutableConstructorProp> | properties.kt:2:53:2:83 | mutableConstructorProp |
3+
| properties.kt:3:5:3:25 | modifiableInt | properties.kt:3:5:3:25 | <get-modifiableInt> | properties.kt:3:5:3:25 | <set-modifiableInt> | properties.kt:3:5:3:25 | modifiableInt |
4+
| properties.kt:4:5:4:24 | immutableInt | properties.kt:4:5:4:24 | <get-immutableInt> | file://:0:0:0:0 | <none> | properties.kt:4:5:4:24 | immutableInt |
5+
| properties.kt:5:5:5:26 | typedProp | properties.kt:5:5:5:26 | <get-typedProp> | file://:0:0:0:0 | <none> | properties.kt:5:5:5:26 | typedProp |
6+
| properties.kt:6:5:6:38 | abstractTypeProp | properties.kt:6:14:6:38 | <get-abstractTypeProp> | file://:0:0:0:0 | <none> | file://:0:0:0:0 | <none> |
7+
| properties.kt:7:5:7:30 | initialisedInInit | properties.kt:7:5:7:30 | <get-initialisedInInit> | file://:0:0:0:0 | <none> | properties.kt:7:5:7:30 | initialisedInInit |
8+
| properties.kt:11:5:11:40 | useConstructorArg | properties.kt:11:5:11:40 | <get-useConstructorArg> | file://:0:0:0:0 | <none> | properties.kt:11:5:11:40 | useConstructorArg |
9+
| properties.kt:12:5:13:21 | five | properties.kt:13:13:13:21 | <get-five> | file://:0:0:0:0 | <none> | file://:0:0:0:0 | <none> |
10+
| properties.kt:14:5:15:21 | six | properties.kt:15:13:15:21 | <get-six> | file://:0:0:0:0 | <none> | file://:0:0:0:0 | <none> |
11+
| properties.kt:16:5:18:40 | getSet | properties.kt:17:13:17:33 | <get-getSet> | properties.kt:18:13:18:40 | <set-getSet> | file://:0:0:0:0 | <none> |
12+
| properties.kt:19:5:20:15 | defaultGetter | properties.kt:20:13:20:15 | <get-defaultGetter> | file://:0:0:0:0 | <none> | properties.kt:19:5:20:15 | defaultGetter |
13+
| properties.kt:21:5:22:15 | varDefaultGetter | properties.kt:22:13:22:15 | <get-varDefaultGetter> | properties.kt:21:5:22:15 | <set-varDefaultGetter> | properties.kt:21:5:22:15 | varDefaultGetter |
14+
| properties.kt:23:5:24:15 | varDefaultSetter | properties.kt:23:5:24:15 | <get-varDefaultSetter> | properties.kt:24:13:24:15 | <set-varDefaultSetter> | properties.kt:23:5:24:15 | varDefaultSetter |
15+
| properties.kt:25:5:27:15 | varDefaultGetterSetter | properties.kt:26:13:26:15 | <get-varDefaultGetterSetter> | properties.kt:27:13:27:15 | <set-varDefaultGetterSetter> | properties.kt:25:5:27:15 | varDefaultGetterSetter |
16+
| properties.kt:28:5:29:22 | overrideGetter | properties.kt:29:13:29:22 | <get-overrideGetter> | properties.kt:28:5:29:22 | <set-overrideGetter> | properties.kt:28:5:29:22 | overrideGetter |
17+
| properties.kt:30:5:31:29 | overrideGetterUseField | properties.kt:31:13:31:29 | <get-overrideGetterUseField> | properties.kt:30:5:31:29 | <set-overrideGetterUseField> | properties.kt:30:5:31:29 | overrideGetterUseField |
18+
| properties.kt:32:5:33:29 | useField | properties.kt:33:13:33:29 | <get-useField> | file://:0:0:0:0 | <none> | properties.kt:32:5:33:29 | useField |
19+
| properties.kt:34:5:34:36 | lateInitVar | properties.kt:34:14:34:36 | <get-lateInitVar> | properties.kt:34:14:34:36 | <set-lateInitVar> | properties.kt:34:5:34:36 | lateInitVar |
20+
| properties.kt:59:1:59:23 | constVal | properties.kt:59:7:59:23 | <get-constVal> | file://:0:0:0:0 | <none> | properties.kt:59:1:59:23 | constVal |
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
2+
abstract class properties(val constructorProp: Int, var mutableConstructorProp: Int, extractorArg: Int) {
3+
var modifiableInt = 1
4+
val immutableInt = 2
5+
val typedProp: Int = 3
6+
abstract val abstractTypeProp: Int
7+
val initialisedInInit: Int
8+
init {
9+
initialisedInInit = 4
10+
}
11+
val useConstructorArg = extractorArg
12+
val five: Int
13+
get() = 5
14+
val six
15+
get() = 6
16+
var getSet
17+
get() = modifiableInt
18+
set(v) { modifiableInt = v }
19+
val defaultGetter = 7
20+
get
21+
var varDefaultGetter = 8
22+
get
23+
var varDefaultSetter = 9
24+
set
25+
var varDefaultGetterSetter = 10
26+
get
27+
set
28+
var overrideGetter = 11
29+
get() = 12
30+
var overrideGetterUseField = 13
31+
get() = field + 1
32+
val useField = 14
33+
get() = field + 1
34+
lateinit var lateInitVar: String
35+
fun useProps(): Int {
36+
return 0 +
37+
constructorProp +
38+
mutableConstructorProp +
39+
modifiableInt +
40+
immutableInt +
41+
typedProp +
42+
abstractTypeProp +
43+
initialisedInInit +
44+
useConstructorArg +
45+
five +
46+
six +
47+
getSet +
48+
defaultGetter +
49+
varDefaultGetter +
50+
varDefaultSetter +
51+
varDefaultGetterSetter +
52+
overrideGetter +
53+
overrideGetterUseField +
54+
useField +
55+
constVal
56+
}
57+
}
58+
59+
const val constVal = 15
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import java
2+
3+
newtype TMaybeElement =
4+
TElement(Element e) or
5+
TNoElement()
6+
7+
class MaybeElement extends TMaybeElement {
8+
abstract string toString();
9+
abstract Location getLocation();
10+
}
11+
12+
class YesMaybeElement extends MaybeElement {
13+
Element e;
14+
15+
YesMaybeElement() { this = TElement(e) }
16+
override string toString() { result = e.toString() }
17+
override Location getLocation() { result = e.getLocation() }
18+
}
19+
20+
class NoMaybeElement extends MaybeElement {
21+
NoMaybeElement() { this = TNoElement() }
22+
23+
override string toString() { result = "<none>" }
24+
override Location getLocation() { none() }
25+
}
26+
27+
MaybeElement getter(Property p) {
28+
if exists(p.getGetter())
29+
then result = TElement(p.getGetter())
30+
else result = TNoElement()
31+
}
32+
33+
MaybeElement setter(Property p) {
34+
if exists(p.getSetter())
35+
then result = TElement(p.getSetter())
36+
else result = TNoElement()
37+
}
38+
39+
MaybeElement backingField(Property p) {
40+
if exists(p.getBackingField())
41+
then result = TElement(p.getBackingField())
42+
else result = TNoElement()
43+
}
44+
45+
from Property p
46+
where p.fromSource()
47+
select p, getter(p), setter(p), backingField(p)
48+

0 commit comments

Comments
 (0)