From b6155ff44352a8d5c687c1fc63c8501041db20c0 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 1 May 2026 18:06:38 +0100 Subject: [PATCH 01/36] Swift: Test spacing. --- .../CWE-328/WeakPasswordHashing.expected | 68 +++++++++---------- .../CWE-328/WeakSensitiveDataHashing.expected | 60 ++++++++-------- .../Security/CWE-328/testCryptoKit.swift | 6 ++ 3 files changed, 70 insertions(+), 64 deletions(-) diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected b/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected index 46f3d211ccd..dfb0f794d96 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected @@ -1,26 +1,26 @@ edges -| testCryptoKit.swift:193:38:193:38 | passwordString | testCryptoKit.swift:193:38:193:53 | .utf8 | provenance | | -| testCryptoKit.swift:193:38:193:53 | .utf8 | testCryptoKit.swift:193:33:193:57 | call to Data.init(_:) | provenance | | +| testCryptoKit.swift:199:38:199:38 | passwordString | testCryptoKit.swift:199:38:199:53 | .utf8 | provenance | | +| testCryptoKit.swift:199:38:199:53 | .utf8 | testCryptoKit.swift:199:33:199:57 | call to Data.init(_:) | provenance | | nodes | testCryptoKit.swift:65:47:65:47 | passwd | semmle.label | passwd | -| testCryptoKit.swift:71:44:71:44 | passwd | semmle.label | passwd | -| testCryptoKit.swift:77:37:77:37 | passwd | semmle.label | passwd | +| testCryptoKit.swift:77:44:77:44 | passwd | semmle.label | passwd | | testCryptoKit.swift:83:37:83:37 | passwd | semmle.label | passwd | | testCryptoKit.swift:89:37:89:37 | passwd | semmle.label | passwd | -| testCryptoKit.swift:98:23:98:23 | passwd | semmle.label | passwd | -| testCryptoKit.swift:107:23:107:23 | passwd | semmle.label | passwd | -| testCryptoKit.swift:116:23:116:23 | passwd | semmle.label | passwd | -| testCryptoKit.swift:125:23:125:23 | passwd | semmle.label | passwd | -| testCryptoKit.swift:134:23:134:23 | passwd | semmle.label | passwd | -| testCryptoKit.swift:143:32:143:32 | passwd | semmle.label | passwd | -| testCryptoKit.swift:152:32:152:32 | passwd | semmle.label | passwd | -| testCryptoKit.swift:161:32:161:32 | passwd | semmle.label | passwd | -| testCryptoKit.swift:170:32:170:32 | passwd | semmle.label | passwd | -| testCryptoKit.swift:179:32:179:32 | passwd | semmle.label | passwd | -| testCryptoKit.swift:189:49:189:49 | passwordData | semmle.label | passwordData | -| testCryptoKit.swift:193:33:193:57 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | -| testCryptoKit.swift:193:38:193:38 | passwordString | semmle.label | passwordString | -| testCryptoKit.swift:193:38:193:53 | .utf8 | semmle.label | .utf8 | +| testCryptoKit.swift:95:37:95:37 | passwd | semmle.label | passwd | +| testCryptoKit.swift:104:23:104:23 | passwd | semmle.label | passwd | +| testCryptoKit.swift:113:23:113:23 | passwd | semmle.label | passwd | +| testCryptoKit.swift:122:23:122:23 | passwd | semmle.label | passwd | +| testCryptoKit.swift:131:23:131:23 | passwd | semmle.label | passwd | +| testCryptoKit.swift:140:23:140:23 | passwd | semmle.label | passwd | +| testCryptoKit.swift:149:32:149:32 | passwd | semmle.label | passwd | +| testCryptoKit.swift:158:32:158:32 | passwd | semmle.label | passwd | +| testCryptoKit.swift:167:32:167:32 | passwd | semmle.label | passwd | +| testCryptoKit.swift:176:32:176:32 | passwd | semmle.label | passwd | +| testCryptoKit.swift:185:32:185:32 | passwd | semmle.label | passwd | +| testCryptoKit.swift:195:49:195:49 | passwordData | semmle.label | passwordData | +| testCryptoKit.swift:199:33:199:57 | call to Data.init(_:) | semmle.label | call to Data.init(_:) | +| testCryptoKit.swift:199:38:199:38 | passwordString | semmle.label | passwordString | +| testCryptoKit.swift:199:38:199:53 | .utf8 | semmle.label | .utf8 | | testCryptoSwift.swift:154:30:154:30 | passwdArray | semmle.label | passwdArray | | testCryptoSwift.swift:157:31:157:31 | passwdArray | semmle.label | passwdArray | | testCryptoSwift.swift:160:47:160:47 | passwdArray | semmle.label | passwdArray | @@ -48,22 +48,22 @@ nodes subpaths #select | testCryptoKit.swift:65:47:65:47 | passwd | testCryptoKit.swift:65:47:65:47 | passwd | testCryptoKit.swift:65:47:65:47 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:65:47:65:47 | passwd | password (passwd) | -| testCryptoKit.swift:71:44:71:44 | passwd | testCryptoKit.swift:71:44:71:44 | passwd | testCryptoKit.swift:71:44:71:44 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:71:44:71:44 | passwd | password (passwd) | -| testCryptoKit.swift:77:37:77:37 | passwd | testCryptoKit.swift:77:37:77:37 | passwd | testCryptoKit.swift:77:37:77:37 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:77:37:77:37 | passwd | password (passwd) | -| testCryptoKit.swift:83:37:83:37 | passwd | testCryptoKit.swift:83:37:83:37 | passwd | testCryptoKit.swift:83:37:83:37 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:83:37:83:37 | passwd | password (passwd) | -| testCryptoKit.swift:89:37:89:37 | passwd | testCryptoKit.swift:89:37:89:37 | passwd | testCryptoKit.swift:89:37:89:37 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:89:37:89:37 | passwd | password (passwd) | -| testCryptoKit.swift:98:23:98:23 | passwd | testCryptoKit.swift:98:23:98:23 | passwd | testCryptoKit.swift:98:23:98:23 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:98:23:98:23 | passwd | password (passwd) | -| testCryptoKit.swift:107:23:107:23 | passwd | testCryptoKit.swift:107:23:107:23 | passwd | testCryptoKit.swift:107:23:107:23 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:107:23:107:23 | passwd | password (passwd) | -| testCryptoKit.swift:116:23:116:23 | passwd | testCryptoKit.swift:116:23:116:23 | passwd | testCryptoKit.swift:116:23:116:23 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:116:23:116:23 | passwd | password (passwd) | -| testCryptoKit.swift:125:23:125:23 | passwd | testCryptoKit.swift:125:23:125:23 | passwd | testCryptoKit.swift:125:23:125:23 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:125:23:125:23 | passwd | password (passwd) | -| testCryptoKit.swift:134:23:134:23 | passwd | testCryptoKit.swift:134:23:134:23 | passwd | testCryptoKit.swift:134:23:134:23 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:134:23:134:23 | passwd | password (passwd) | -| testCryptoKit.swift:143:32:143:32 | passwd | testCryptoKit.swift:143:32:143:32 | passwd | testCryptoKit.swift:143:32:143:32 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:143:32:143:32 | passwd | password (passwd) | -| testCryptoKit.swift:152:32:152:32 | passwd | testCryptoKit.swift:152:32:152:32 | passwd | testCryptoKit.swift:152:32:152:32 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:152:32:152:32 | passwd | password (passwd) | -| testCryptoKit.swift:161:32:161:32 | passwd | testCryptoKit.swift:161:32:161:32 | passwd | testCryptoKit.swift:161:32:161:32 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:161:32:161:32 | passwd | password (passwd) | -| testCryptoKit.swift:170:32:170:32 | passwd | testCryptoKit.swift:170:32:170:32 | passwd | testCryptoKit.swift:170:32:170:32 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:170:32:170:32 | passwd | password (passwd) | -| testCryptoKit.swift:179:32:179:32 | passwd | testCryptoKit.swift:179:32:179:32 | passwd | testCryptoKit.swift:179:32:179:32 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:179:32:179:32 | passwd | password (passwd) | -| testCryptoKit.swift:189:49:189:49 | passwordData | testCryptoKit.swift:189:49:189:49 | passwordData | testCryptoKit.swift:189:49:189:49 | passwordData | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:189:49:189:49 | passwordData | password (passwordData) | -| testCryptoKit.swift:193:33:193:57 | call to Data.init(_:) | testCryptoKit.swift:193:38:193:38 | passwordString | testCryptoKit.swift:193:33:193:57 | call to Data.init(_:) | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:193:38:193:38 | passwordString | password (passwordString) | +| testCryptoKit.swift:77:44:77:44 | passwd | testCryptoKit.swift:77:44:77:44 | passwd | testCryptoKit.swift:77:44:77:44 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:77:44:77:44 | passwd | password (passwd) | +| testCryptoKit.swift:83:37:83:37 | passwd | testCryptoKit.swift:83:37:83:37 | passwd | testCryptoKit.swift:83:37:83:37 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:83:37:83:37 | passwd | password (passwd) | +| testCryptoKit.swift:89:37:89:37 | passwd | testCryptoKit.swift:89:37:89:37 | passwd | testCryptoKit.swift:89:37:89:37 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:89:37:89:37 | passwd | password (passwd) | +| testCryptoKit.swift:95:37:95:37 | passwd | testCryptoKit.swift:95:37:95:37 | passwd | testCryptoKit.swift:95:37:95:37 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:95:37:95:37 | passwd | password (passwd) | +| testCryptoKit.swift:104:23:104:23 | passwd | testCryptoKit.swift:104:23:104:23 | passwd | testCryptoKit.swift:104:23:104:23 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:104:23:104:23 | passwd | password (passwd) | +| testCryptoKit.swift:113:23:113:23 | passwd | testCryptoKit.swift:113:23:113:23 | passwd | testCryptoKit.swift:113:23:113:23 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:113:23:113:23 | passwd | password (passwd) | +| testCryptoKit.swift:122:23:122:23 | passwd | testCryptoKit.swift:122:23:122:23 | passwd | testCryptoKit.swift:122:23:122:23 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:122:23:122:23 | passwd | password (passwd) | +| testCryptoKit.swift:131:23:131:23 | passwd | testCryptoKit.swift:131:23:131:23 | passwd | testCryptoKit.swift:131:23:131:23 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:131:23:131:23 | passwd | password (passwd) | +| testCryptoKit.swift:140:23:140:23 | passwd | testCryptoKit.swift:140:23:140:23 | passwd | testCryptoKit.swift:140:23:140:23 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:140:23:140:23 | passwd | password (passwd) | +| testCryptoKit.swift:149:32:149:32 | passwd | testCryptoKit.swift:149:32:149:32 | passwd | testCryptoKit.swift:149:32:149:32 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:149:32:149:32 | passwd | password (passwd) | +| testCryptoKit.swift:158:32:158:32 | passwd | testCryptoKit.swift:158:32:158:32 | passwd | testCryptoKit.swift:158:32:158:32 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:158:32:158:32 | passwd | password (passwd) | +| testCryptoKit.swift:167:32:167:32 | passwd | testCryptoKit.swift:167:32:167:32 | passwd | testCryptoKit.swift:167:32:167:32 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:167:32:167:32 | passwd | password (passwd) | +| testCryptoKit.swift:176:32:176:32 | passwd | testCryptoKit.swift:176:32:176:32 | passwd | testCryptoKit.swift:176:32:176:32 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:176:32:176:32 | passwd | password (passwd) | +| testCryptoKit.swift:185:32:185:32 | passwd | testCryptoKit.swift:185:32:185:32 | passwd | testCryptoKit.swift:185:32:185:32 | passwd | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:185:32:185:32 | passwd | password (passwd) | +| testCryptoKit.swift:195:49:195:49 | passwordData | testCryptoKit.swift:195:49:195:49 | passwordData | testCryptoKit.swift:195:49:195:49 | passwordData | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:195:49:195:49 | passwordData | password (passwordData) | +| testCryptoKit.swift:199:33:199:57 | call to Data.init(_:) | testCryptoKit.swift:199:38:199:38 | passwordString | testCryptoKit.swift:199:33:199:57 | call to Data.init(_:) | Insecure hashing algorithm (SHA512) depends on $@. | testCryptoKit.swift:199:38:199:38 | passwordString | password (passwordString) | | testCryptoSwift.swift:154:30:154:30 | passwdArray | testCryptoSwift.swift:154:30:154:30 | passwdArray | testCryptoSwift.swift:154:30:154:30 | passwdArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:154:30:154:30 | passwdArray | password (passwdArray) | | testCryptoSwift.swift:157:31:157:31 | passwdArray | testCryptoSwift.swift:157:31:157:31 | passwdArray | testCryptoSwift.swift:157:31:157:31 | passwdArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:157:31:157:31 | passwdArray | password (passwdArray) | | testCryptoSwift.swift:160:47:160:47 | passwdArray | testCryptoSwift.swift:160:47:160:47 | passwdArray | testCryptoSwift.swift:160:47:160:47 | passwdArray | Insecure hashing algorithm (SHA2) depends on $@. | testCryptoSwift.swift:160:47:160:47 | passwdArray | password (passwdArray) | diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected index 2cd31692f8d..f65f4798deb 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected @@ -3,21 +3,21 @@ nodes | testCryptoKit.swift:66:43:66:43 | cert | semmle.label | cert | | testCryptoKit.swift:68:43:68:43 | account_no | semmle.label | account_no | | testCryptoKit.swift:69:43:69:43 | credit_card_no | semmle.label | credit_card_no | -| testCryptoKit.swift:72:44:72:44 | cert | semmle.label | cert | -| testCryptoKit.swift:74:44:74:44 | account_no | semmle.label | account_no | -| testCryptoKit.swift:75:44:75:44 | credit_card_no | semmle.label | credit_card_no | -| testCryptoKit.swift:99:23:99:23 | cert | semmle.label | cert | -| testCryptoKit.swift:101:23:101:23 | account_no | semmle.label | account_no | -| testCryptoKit.swift:102:23:102:23 | credit_card_no | semmle.label | credit_card_no | -| testCryptoKit.swift:108:23:108:23 | cert | semmle.label | cert | -| testCryptoKit.swift:110:23:110:23 | account_no | semmle.label | account_no | -| testCryptoKit.swift:111:23:111:23 | credit_card_no | semmle.label | credit_card_no | -| testCryptoKit.swift:144:32:144:32 | cert | semmle.label | cert | -| testCryptoKit.swift:146:32:146:32 | account_no | semmle.label | account_no | -| testCryptoKit.swift:147:32:147:32 | credit_card_no | semmle.label | credit_card_no | -| testCryptoKit.swift:153:32:153:32 | cert | semmle.label | cert | -| testCryptoKit.swift:155:32:155:32 | account_no | semmle.label | account_no | -| testCryptoKit.swift:156:32:156:32 | credit_card_no | semmle.label | credit_card_no | +| testCryptoKit.swift:78:44:78:44 | cert | semmle.label | cert | +| testCryptoKit.swift:80:44:80:44 | account_no | semmle.label | account_no | +| testCryptoKit.swift:81:44:81:44 | credit_card_no | semmle.label | credit_card_no | +| testCryptoKit.swift:105:23:105:23 | cert | semmle.label | cert | +| testCryptoKit.swift:107:23:107:23 | account_no | semmle.label | account_no | +| testCryptoKit.swift:108:23:108:23 | credit_card_no | semmle.label | credit_card_no | +| testCryptoKit.swift:114:23:114:23 | cert | semmle.label | cert | +| testCryptoKit.swift:116:23:116:23 | account_no | semmle.label | account_no | +| testCryptoKit.swift:117:23:117:23 | credit_card_no | semmle.label | credit_card_no | +| testCryptoKit.swift:150:32:150:32 | cert | semmle.label | cert | +| testCryptoKit.swift:152:32:152:32 | account_no | semmle.label | account_no | +| testCryptoKit.swift:153:32:153:32 | credit_card_no | semmle.label | credit_card_no | +| testCryptoKit.swift:159:32:159:32 | cert | semmle.label | cert | +| testCryptoKit.swift:161:32:161:32 | account_no | semmle.label | account_no | +| testCryptoKit.swift:162:32:162:32 | credit_card_no | semmle.label | credit_card_no | | testCryptoSwift.swift:153:30:153:30 | phoneNumberArray | semmle.label | phoneNumberArray | | testCryptoSwift.swift:156:31:156:31 | phoneNumberArray | semmle.label | phoneNumberArray | | testCryptoSwift.swift:166:20:166:20 | phoneNumberArray | semmle.label | phoneNumberArray | @@ -33,21 +33,21 @@ subpaths | testCryptoKit.swift:66:43:66:43 | cert | testCryptoKit.swift:66:43:66:43 | cert | testCryptoKit.swift:66:43:66:43 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:66:43:66:43 | cert | sensitive data (credential cert) | | testCryptoKit.swift:68:43:68:43 | account_no | testCryptoKit.swift:68:43:68:43 | account_no | testCryptoKit.swift:68:43:68:43 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:68:43:68:43 | account_no | sensitive data (private information account_no) | | testCryptoKit.swift:69:43:69:43 | credit_card_no | testCryptoKit.swift:69:43:69:43 | credit_card_no | testCryptoKit.swift:69:43:69:43 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:69:43:69:43 | credit_card_no | sensitive data (private information credit_card_no) | -| testCryptoKit.swift:72:44:72:44 | cert | testCryptoKit.swift:72:44:72:44 | cert | testCryptoKit.swift:72:44:72:44 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:72:44:72:44 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:74:44:74:44 | account_no | testCryptoKit.swift:74:44:74:44 | account_no | testCryptoKit.swift:74:44:74:44 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:74:44:74:44 | account_no | sensitive data (private information account_no) | -| testCryptoKit.swift:75:44:75:44 | credit_card_no | testCryptoKit.swift:75:44:75:44 | credit_card_no | testCryptoKit.swift:75:44:75:44 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:75:44:75:44 | credit_card_no | sensitive data (private information credit_card_no) | -| testCryptoKit.swift:99:23:99:23 | cert | testCryptoKit.swift:99:23:99:23 | cert | testCryptoKit.swift:99:23:99:23 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:99:23:99:23 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:101:23:101:23 | account_no | testCryptoKit.swift:101:23:101:23 | account_no | testCryptoKit.swift:101:23:101:23 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:101:23:101:23 | account_no | sensitive data (private information account_no) | -| testCryptoKit.swift:102:23:102:23 | credit_card_no | testCryptoKit.swift:102:23:102:23 | credit_card_no | testCryptoKit.swift:102:23:102:23 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:102:23:102:23 | credit_card_no | sensitive data (private information credit_card_no) | -| testCryptoKit.swift:108:23:108:23 | cert | testCryptoKit.swift:108:23:108:23 | cert | testCryptoKit.swift:108:23:108:23 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:108:23:108:23 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:110:23:110:23 | account_no | testCryptoKit.swift:110:23:110:23 | account_no | testCryptoKit.swift:110:23:110:23 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:110:23:110:23 | account_no | sensitive data (private information account_no) | -| testCryptoKit.swift:111:23:111:23 | credit_card_no | testCryptoKit.swift:111:23:111:23 | credit_card_no | testCryptoKit.swift:111:23:111:23 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:111:23:111:23 | credit_card_no | sensitive data (private information credit_card_no) | -| testCryptoKit.swift:144:32:144:32 | cert | testCryptoKit.swift:144:32:144:32 | cert | testCryptoKit.swift:144:32:144:32 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:144:32:144:32 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:146:32:146:32 | account_no | testCryptoKit.swift:146:32:146:32 | account_no | testCryptoKit.swift:146:32:146:32 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:146:32:146:32 | account_no | sensitive data (private information account_no) | -| testCryptoKit.swift:147:32:147:32 | credit_card_no | testCryptoKit.swift:147:32:147:32 | credit_card_no | testCryptoKit.swift:147:32:147:32 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:147:32:147:32 | credit_card_no | sensitive data (private information credit_card_no) | -| testCryptoKit.swift:153:32:153:32 | cert | testCryptoKit.swift:153:32:153:32 | cert | testCryptoKit.swift:153:32:153:32 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:153:32:153:32 | cert | sensitive data (credential cert) | -| testCryptoKit.swift:155:32:155:32 | account_no | testCryptoKit.swift:155:32:155:32 | account_no | testCryptoKit.swift:155:32:155:32 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:155:32:155:32 | account_no | sensitive data (private information account_no) | -| testCryptoKit.swift:156:32:156:32 | credit_card_no | testCryptoKit.swift:156:32:156:32 | credit_card_no | testCryptoKit.swift:156:32:156:32 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:156:32:156:32 | credit_card_no | sensitive data (private information credit_card_no) | +| testCryptoKit.swift:78:44:78:44 | cert | testCryptoKit.swift:78:44:78:44 | cert | testCryptoKit.swift:78:44:78:44 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:78:44:78:44 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:80:44:80:44 | account_no | testCryptoKit.swift:80:44:80:44 | account_no | testCryptoKit.swift:80:44:80:44 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:80:44:80:44 | account_no | sensitive data (private information account_no) | +| testCryptoKit.swift:81:44:81:44 | credit_card_no | testCryptoKit.swift:81:44:81:44 | credit_card_no | testCryptoKit.swift:81:44:81:44 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:81:44:81:44 | credit_card_no | sensitive data (private information credit_card_no) | +| testCryptoKit.swift:105:23:105:23 | cert | testCryptoKit.swift:105:23:105:23 | cert | testCryptoKit.swift:105:23:105:23 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:105:23:105:23 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:107:23:107:23 | account_no | testCryptoKit.swift:107:23:107:23 | account_no | testCryptoKit.swift:107:23:107:23 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:107:23:107:23 | account_no | sensitive data (private information account_no) | +| testCryptoKit.swift:108:23:108:23 | credit_card_no | testCryptoKit.swift:108:23:108:23 | credit_card_no | testCryptoKit.swift:108:23:108:23 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:108:23:108:23 | credit_card_no | sensitive data (private information credit_card_no) | +| testCryptoKit.swift:114:23:114:23 | cert | testCryptoKit.swift:114:23:114:23 | cert | testCryptoKit.swift:114:23:114:23 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:114:23:114:23 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:116:23:116:23 | account_no | testCryptoKit.swift:116:23:116:23 | account_no | testCryptoKit.swift:116:23:116:23 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:116:23:116:23 | account_no | sensitive data (private information account_no) | +| testCryptoKit.swift:117:23:117:23 | credit_card_no | testCryptoKit.swift:117:23:117:23 | credit_card_no | testCryptoKit.swift:117:23:117:23 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:117:23:117:23 | credit_card_no | sensitive data (private information credit_card_no) | +| testCryptoKit.swift:150:32:150:32 | cert | testCryptoKit.swift:150:32:150:32 | cert | testCryptoKit.swift:150:32:150:32 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:150:32:150:32 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:152:32:152:32 | account_no | testCryptoKit.swift:152:32:152:32 | account_no | testCryptoKit.swift:152:32:152:32 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:152:32:152:32 | account_no | sensitive data (private information account_no) | +| testCryptoKit.swift:153:32:153:32 | credit_card_no | testCryptoKit.swift:153:32:153:32 | credit_card_no | testCryptoKit.swift:153:32:153:32 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:153:32:153:32 | credit_card_no | sensitive data (private information credit_card_no) | +| testCryptoKit.swift:159:32:159:32 | cert | testCryptoKit.swift:159:32:159:32 | cert | testCryptoKit.swift:159:32:159:32 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:159:32:159:32 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:161:32:161:32 | account_no | testCryptoKit.swift:161:32:161:32 | account_no | testCryptoKit.swift:161:32:161:32 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:161:32:161:32 | account_no | sensitive data (private information account_no) | +| testCryptoKit.swift:162:32:162:32 | credit_card_no | testCryptoKit.swift:162:32:162:32 | credit_card_no | testCryptoKit.swift:162:32:162:32 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:162:32:162:32 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoSwift.swift:153:30:153:30 | phoneNumberArray | testCryptoSwift.swift:153:30:153:30 | phoneNumberArray | testCryptoSwift.swift:153:30:153:30 | phoneNumberArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:153:30:153:30 | phoneNumberArray | sensitive data (private information phoneNumberArray) | | testCryptoSwift.swift:156:31:156:31 | phoneNumberArray | testCryptoSwift.swift:156:31:156:31 | phoneNumberArray | testCryptoSwift.swift:156:31:156:31 | phoneNumberArray | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoSwift.swift:156:31:156:31 | phoneNumberArray | sensitive data (private information phoneNumberArray) | | testCryptoSwift.swift:166:20:166:20 | phoneNumberArray | testCryptoSwift.swift:166:20:166:20 | phoneNumberArray | testCryptoSwift.swift:166:20:166:20 | phoneNumberArray | Insecure hashing algorithm (MD5) depends on $@. | testCryptoSwift.swift:166:20:166:20 | phoneNumberArray | sensitive data (private information phoneNumberArray) | diff --git a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift index dd37c6238c0..80481526058 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift +++ b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift @@ -68,6 +68,12 @@ func testHashMethods(passwd : UnsafeRawBufferPointer, cert: String, encrypted_pa hash = Crypto.Insecure.MD5.hash(data: account_no) // BAD hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // BAD + + + + + + hash = Crypto.Insecure.SHA1.hash(data: passwd) // BAD hash = Crypto.Insecure.SHA1.hash(data: cert) // BAD hash = Crypto.Insecure.SHA1.hash(data: encrypted_passwd) // GOOD (not sensitive) From dc863c39a9ece4feef77b1f782f76b94316ccac1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 1 May 2026 18:12:06 +0100 Subject: [PATCH 02/36] Swift: Add test cases for an alternative pattern of calls to Insecure.MD5.hash. --- .../Security/CWE-328/WeakPasswordHashing.expected | 2 ++ .../Security/CWE-328/WeakSensitiveDataHashing.expected | 6 ++++++ .../query-tests/Security/CWE-328/testCryptoKit.swift | 10 +++++----- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected b/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected index dfb0f794d96..f8db62cedbc 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakPasswordHashing.expected @@ -3,6 +3,7 @@ edges | testCryptoKit.swift:199:38:199:53 | .utf8 | testCryptoKit.swift:199:33:199:57 | call to Data.init(_:) | provenance | | nodes | testCryptoKit.swift:65:47:65:47 | passwd | semmle.label | passwd | +| testCryptoKit.swift:71:36:71:36 | passwd | semmle.label | passwd | | testCryptoKit.swift:77:44:77:44 | passwd | semmle.label | passwd | | testCryptoKit.swift:83:37:83:37 | passwd | semmle.label | passwd | | testCryptoKit.swift:89:37:89:37 | passwd | semmle.label | passwd | @@ -48,6 +49,7 @@ nodes subpaths #select | testCryptoKit.swift:65:47:65:47 | passwd | testCryptoKit.swift:65:47:65:47 | passwd | testCryptoKit.swift:65:47:65:47 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:65:47:65:47 | passwd | password (passwd) | +| testCryptoKit.swift:71:36:71:36 | passwd | testCryptoKit.swift:71:36:71:36 | passwd | testCryptoKit.swift:71:36:71:36 | passwd | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:71:36:71:36 | passwd | password (passwd) | | testCryptoKit.swift:77:44:77:44 | passwd | testCryptoKit.swift:77:44:77:44 | passwd | testCryptoKit.swift:77:44:77:44 | passwd | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:77:44:77:44 | passwd | password (passwd) | | testCryptoKit.swift:83:37:83:37 | passwd | testCryptoKit.swift:83:37:83:37 | passwd | testCryptoKit.swift:83:37:83:37 | passwd | Insecure hashing algorithm (SHA256) depends on $@. | testCryptoKit.swift:83:37:83:37 | passwd | password (passwd) | | testCryptoKit.swift:89:37:89:37 | passwd | testCryptoKit.swift:89:37:89:37 | passwd | testCryptoKit.swift:89:37:89:37 | passwd | Insecure hashing algorithm (SHA384) depends on $@. | testCryptoKit.swift:89:37:89:37 | passwd | password (passwd) | diff --git a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected index f65f4798deb..5da99db8068 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected +++ b/swift/ql/test/query-tests/Security/CWE-328/WeakSensitiveDataHashing.expected @@ -3,6 +3,9 @@ nodes | testCryptoKit.swift:66:43:66:43 | cert | semmle.label | cert | | testCryptoKit.swift:68:43:68:43 | account_no | semmle.label | account_no | | testCryptoKit.swift:69:43:69:43 | credit_card_no | semmle.label | credit_card_no | +| testCryptoKit.swift:72:36:72:36 | cert | semmle.label | cert | +| testCryptoKit.swift:74:36:74:36 | account_no | semmle.label | account_no | +| testCryptoKit.swift:75:36:75:36 | credit_card_no | semmle.label | credit_card_no | | testCryptoKit.swift:78:44:78:44 | cert | semmle.label | cert | | testCryptoKit.swift:80:44:80:44 | account_no | semmle.label | account_no | | testCryptoKit.swift:81:44:81:44 | credit_card_no | semmle.label | credit_card_no | @@ -33,6 +36,9 @@ subpaths | testCryptoKit.swift:66:43:66:43 | cert | testCryptoKit.swift:66:43:66:43 | cert | testCryptoKit.swift:66:43:66:43 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:66:43:66:43 | cert | sensitive data (credential cert) | | testCryptoKit.swift:68:43:68:43 | account_no | testCryptoKit.swift:68:43:68:43 | account_no | testCryptoKit.swift:68:43:68:43 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:68:43:68:43 | account_no | sensitive data (private information account_no) | | testCryptoKit.swift:69:43:69:43 | credit_card_no | testCryptoKit.swift:69:43:69:43 | credit_card_no | testCryptoKit.swift:69:43:69:43 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:69:43:69:43 | credit_card_no | sensitive data (private information credit_card_no) | +| testCryptoKit.swift:72:36:72:36 | cert | testCryptoKit.swift:72:36:72:36 | cert | testCryptoKit.swift:72:36:72:36 | cert | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:72:36:72:36 | cert | sensitive data (credential cert) | +| testCryptoKit.swift:74:36:74:36 | account_no | testCryptoKit.swift:74:36:74:36 | account_no | testCryptoKit.swift:74:36:74:36 | account_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:74:36:74:36 | account_no | sensitive data (private information account_no) | +| testCryptoKit.swift:75:36:75:36 | credit_card_no | testCryptoKit.swift:75:36:75:36 | credit_card_no | testCryptoKit.swift:75:36:75:36 | credit_card_no | Insecure hashing algorithm (MD5) depends on $@. | testCryptoKit.swift:75:36:75:36 | credit_card_no | sensitive data (private information credit_card_no) | | testCryptoKit.swift:78:44:78:44 | cert | testCryptoKit.swift:78:44:78:44 | cert | testCryptoKit.swift:78:44:78:44 | cert | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:78:44:78:44 | cert | sensitive data (credential cert) | | testCryptoKit.swift:80:44:80:44 | account_no | testCryptoKit.swift:80:44:80:44 | account_no | testCryptoKit.swift:80:44:80:44 | account_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:80:44:80:44 | account_no | sensitive data (private information account_no) | | testCryptoKit.swift:81:44:81:44 | credit_card_no | testCryptoKit.swift:81:44:81:44 | credit_card_no | testCryptoKit.swift:81:44:81:44 | credit_card_no | Insecure hashing algorithm (SHA1) depends on $@. | testCryptoKit.swift:81:44:81:44 | credit_card_no | sensitive data (private information credit_card_no) | diff --git a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift index 80481526058..755bd27e3c7 100644 --- a/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift +++ b/swift/ql/test/query-tests/Security/CWE-328/testCryptoKit.swift @@ -68,11 +68,11 @@ func testHashMethods(passwd : UnsafeRawBufferPointer, cert: String, encrypted_pa hash = Crypto.Insecure.MD5.hash(data: account_no) // BAD hash = Crypto.Insecure.MD5.hash(data: credit_card_no) // BAD - - - - - + hash = Insecure.MD5.hash(data: passwd) // BAD + hash = Insecure.MD5.hash(data: cert) // BAD + hash = Insecure.MD5.hash(data: encrypted_passwd) // GOOD (not sensitive) + hash = Insecure.MD5.hash(data: account_no) // BAD + hash = Insecure.MD5.hash(data: credit_card_no) // BAD hash = Crypto.Insecure.SHA1.hash(data: passwd) // BAD hash = Crypto.Insecure.SHA1.hash(data: cert) // BAD From d95001f4069fab17ce172243bbe426ace747b730 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 May 2026 10:46:09 +0100 Subject: [PATCH 03/36] Rust: Additional test cases for sensitive data heuristics. --- .../test/library-tests/sensitivedata/test.rs | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index f8d850beeb8..9b0581239de 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -23,11 +23,14 @@ impl MyStruct { fn get_password() -> String { get_string() } fn test_passwords( - password: &str, pass_word: &str, passwd: &str, my_password: &str, password_str: &str, password_confirmation: &str, + password: &str, pass_word: &str, passwd: &str, my_password: &str, password_str: &str, password_confirmation: &str, profile_password: &str, pass_phrase: &str, passphrase: &str, passPhrase: &str, backup_code: &str, auth_key: &str, authkey: &str, authKey: &str, authentication_key: &str, authenticationkey: &str, authenticationKey: &str, oauth: &str, - one_time_code: &str, - harmless: &str, encrypted_password: &str, password_hash: &str, passwordFile: &str, + one_time_code: &str, api_token: &str, api_tok: &str, + harmless: &str, + encrypted_password: &str, unencrypted_password: &str, encoded_password: &str, unencoded_password: &str, + password_hash: &str, passwordFile: &str, coauthor: &str, + ms: &MyStruct ) { // passwords @@ -38,6 +41,9 @@ fn test_passwords( sink(my_password); // $ sensitive=password sink(password_str); // $ sensitive=password sink(password_confirmation); // $ sensitive=password + sink(profile_password); // $ MISSING: sensitive=password + sink(unencrypted_password); // $ MISSING: sensitive=password + sink(unencoded_password); // $ MISSING: sensitive=password sink(pass_phrase); // $ sensitive=password sink(passphrase); // $ sensitive=password sink(passPhrase); // $ sensitive=password @@ -51,6 +57,8 @@ fn test_passwords( sink(authenticationKey); // $ sensitive=password sink(oauth); // $ sensitive=password sink(one_time_code); // $ MISSING: sensitive=password + sink(api_token); // $ sensitive=password + sink(api_tok); // $ MISSING: sensitive=password sink(ms); // $ MISSING: sensitive=password sink(ms.password.as_str()); // $ sensitive=password @@ -67,8 +75,10 @@ fn test_passwords( sink(harmless); sink(encrypted_password); + sink(encoded_password); sink(password_hash); sink(passwordFile); + sink(coauthor); // $ SPURIOUS: sensitive=password sink(ms.harmless.as_str()); sink(ms.password_file_path.as_str()); @@ -187,6 +197,10 @@ struct Financials { harmless: String, my_bank_account_number: String, credit_card_no: String, + card_no: String, + cardNumber: String, + card_security_code: String, + credit_rating: i32, user_ccn: String, cvv: String, @@ -201,6 +215,7 @@ struct Financials { accounting: i32, unaccounted: bool, multiband: bool, + wildcard_not_matched: bool, } enum Gender { @@ -298,6 +313,9 @@ fn test_private_info( sink(info.financials.my_bank_account_number.as_str()); // $ sensitive=private SPURIOUS: sensitive=id sink(info.financials.credit_card_no.as_str()); // $ sensitive=private + sink(info.financials.card_no.as_str()); // $ MISSING: sensitive=private + sink(info.financials.cardNumber.as_str()); // $ MISSING: sensitive=private + sink(info.financials.card_security_code.as_str()); // $ MISSING: sensitive=private sink(info.financials.credit_rating); // $ sensitive=private sink(info.financials.user_ccn.as_str()); // $ sensitive=private sink(info.financials.cvv.as_str()); // $ sensitive=private @@ -350,6 +368,7 @@ fn test_private_info( sink(info.financials.accounting); sink(info.financials.unaccounted); sink(info.financials.multiband); + sink(info.financials.wildcard_not_matched); sink(ContactDetails::FavouriteColor("blue".to_string())); } From 07d4df18b911584c2058ca1b8311253dbdc4d91c Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 May 2026 11:28:41 +0100 Subject: [PATCH 04/36] Shared: Add 'card.?no' sensitive data heuristic. --- rust/ql/test/library-tests/sensitivedata/test.rs | 6 +++--- .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index 9b0581239de..a5af8efeab4 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -313,8 +313,8 @@ fn test_private_info( sink(info.financials.my_bank_account_number.as_str()); // $ sensitive=private SPURIOUS: sensitive=id sink(info.financials.credit_card_no.as_str()); // $ sensitive=private - sink(info.financials.card_no.as_str()); // $ MISSING: sensitive=private - sink(info.financials.cardNumber.as_str()); // $ MISSING: sensitive=private + sink(info.financials.card_no.as_str()); // $ sensitive=private + sink(info.financials.cardNumber.as_str()); // $ sensitive=private sink(info.financials.card_security_code.as_str()); // $ MISSING: sensitive=private sink(info.financials.credit_rating); // $ sensitive=private sink(info.financials.user_ccn.as_str()); // $ sensitive=private @@ -368,7 +368,7 @@ fn test_private_info( sink(info.financials.accounting); sink(info.financials.unaccounted); sink(info.financials.multiband); - sink(info.financials.wildcard_not_matched); + sink(info.financials.wildcard_not_matched); // $ SPURIOUS: sensitive=private sink(ContactDetails::FavouriteColor("blue".to_string())); } diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index 4271784577f..c30a834fbd5 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -104,7 +104,7 @@ module HeuristicNames { // Geographic location - where the user is (or was) "latitude|longitude|nationality|" + // Financial data - such as credit card numbers, salary, bank accounts, and debts - "(credit|debit|bank|visa).?(card|num|no|acc(ou)?nt)|acc(ou)?nt.?(no|num|credit)|routing.?num|" + "(credit|debit|bank|visa).?(card|num|no|acc(ou)?nt)|(card|acc(ou)?nt).?(no|num|credit)|routing.?num|" + "salary|billing|beneficiary|credit.?(rating|score)|([_-]|\\b)(ccn|cvv|iban)([_-]|\\b)|" + // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. // "e(mail|_mail)|" + // this seems too noisy From cb84e633fa647d4713b09fbbd8f741912da4d992 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 May 2026 11:52:05 +0100 Subject: [PATCH 05/36] Shared: Fix for 'wildcard'. --- rust/ql/test/library-tests/sensitivedata/test.rs | 2 +- .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index a5af8efeab4..db834b54b06 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -368,7 +368,7 @@ fn test_private_info( sink(info.financials.accounting); sink(info.financials.unaccounted); sink(info.financials.multiband); - sink(info.financials.wildcard_not_matched); // $ SPURIOUS: sensitive=private + sink(info.financials.wildcard_not_matched); sink(ContactDetails::FavouriteColor("blue".to_string())); } diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index c30a834fbd5..32045c783c7 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -145,13 +145,13 @@ module HeuristicNames { * suggesting nouns within the string do not represent the meaning of the whole string (e.g. a URL or a SQL query). * * We also filter out common words like `certain` and `concert`, since otherwise these could - * be matched by the certificate regular expressions. Same for `accountable` (account), or - * `secretarial` (secret). + * be matched by the certificate regular expressions. Same for `accountable` (account), + * `secretarial` (secret), `wildcard` (card). */ string notSensitiveRegexp() { result = "(?is).*([^\\w$.-]|redact|censor|obfuscate|hash|md5|sha|random|((? Date: Wed, 6 May 2026 12:00:06 +0100 Subject: [PATCH 06/36] Shared: Fix for 'profile'. --- rust/ql/test/library-tests/sensitivedata/test.rs | 2 +- .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index db834b54b06..a85db97fb72 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -41,7 +41,7 @@ fn test_passwords( sink(my_password); // $ sensitive=password sink(password_str); // $ sensitive=password sink(password_confirmation); // $ sensitive=password - sink(profile_password); // $ MISSING: sensitive=password + sink(profile_password); // $ sensitive=password sink(unencrypted_password); // $ MISSING: sensitive=password sink(unencoded_password); // $ MISSING: sensitive=password sink(pass_phrase); // $ sensitive=password diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index 32045c783c7..0f66d5b6c4f 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -151,7 +151,7 @@ module HeuristicNames { string notSensitiveRegexp() { result = "(?is).*([^\\w$.-]|redact|censor|obfuscate|hash|md5|sha|random|((? Date: Wed, 6 May 2026 12:04:59 +0100 Subject: [PATCH 07/36] Shared: Fix for 'api_tok'. --- rust/ql/test/library-tests/sensitivedata/test.rs | 2 +- .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index a85db97fb72..1e1eca6a42b 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -58,7 +58,7 @@ fn test_passwords( sink(oauth); // $ sensitive=password sink(one_time_code); // $ MISSING: sensitive=password sink(api_token); // $ sensitive=password - sink(api_tok); // $ MISSING: sensitive=password + sink(api_tok); // $ sensitive=password sink(ms); // $ MISSING: sensitive=password sink(ms.password.as_str()); // $ sensitive=password diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index 0f66d5b6c4f..9cc414ef85f 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -76,7 +76,7 @@ module HeuristicNames { string maybePassword() { result = "(?is).*(pass(wd|word|code|.?phrase)(?!.*question)|(auth(entication|ori[sz]ation)?).?key|oauth|" - + "api.?(key|token)|([_-]|\\b)mfa([_-]|\\b)).*" + + "api.?(key|tok)|([_-]|\\b)mfa([_-]|\\b)).*" } /** From 6e2fb6f0ff5fb048dbdd17068abdee84d8df73c8 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 6 May 2026 12:06:55 +0100 Subject: [PATCH 08/36] Shared: Fix for 'coauthor'. --- rust/ql/test/library-tests/sensitivedata/test.rs | 2 +- .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index 1e1eca6a42b..81ef1b782ea 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -78,7 +78,7 @@ fn test_passwords( sink(encoded_password); sink(password_hash); sink(passwordFile); - sink(coauthor); // $ SPURIOUS: sensitive=password + sink(coauthor); sink(ms.harmless.as_str()); sink(ms.password_file_path.as_str()); diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index 9cc414ef85f..c16478902e4 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -146,12 +146,12 @@ module HeuristicNames { * * We also filter out common words like `certain` and `concert`, since otherwise these could * be matched by the certificate regular expressions. Same for `accountable` (account), - * `secretarial` (secret), `wildcard` (card). + * `secretarial` (secret), `wildcard` (card), `coauthor` (oauth). */ string notSensitiveRegexp() { result = "(?is).*([^\\w$.-]|redact|censor|obfuscate|hash|md5|sha|random|((? Date: Wed, 6 May 2026 14:43:23 +0100 Subject: [PATCH 09/36] Shared: Fix and simplify the exclusion for 'encrypted' values. --- rust/ql/test/library-tests/sensitivedata/test.rs | 4 ++-- .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index 81ef1b782ea..2fa22152c83 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -42,8 +42,8 @@ fn test_passwords( sink(password_str); // $ sensitive=password sink(password_confirmation); // $ sensitive=password sink(profile_password); // $ sensitive=password - sink(unencrypted_password); // $ MISSING: sensitive=password - sink(unencoded_password); // $ MISSING: sensitive=password + sink(unencrypted_password); // $ sensitive=password + sink(unencoded_password); // $ sensitive=password sink(pass_phrase); // $ sensitive=password sink(passphrase); // $ sensitive=password sink(passPhrase); // $ sensitive=password diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index c16478902e4..80ef76c76ac 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -150,7 +150,7 @@ module HeuristicNames { */ string notSensitiveRegexp() { result = - "(?is).*([^\\w$.-]|redact|censor|obfuscate|hash|md5|sha|random|((? Date: Wed, 6 May 2026 14:19:08 +0100 Subject: [PATCH 10/36] Shared: Add 'security_code' sensitive data heuristic. --- rust/ql/test/library-tests/sensitivedata/test.rs | 2 +- .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/ql/test/library-tests/sensitivedata/test.rs b/rust/ql/test/library-tests/sensitivedata/test.rs index 2fa22152c83..e2bb5a5f595 100644 --- a/rust/ql/test/library-tests/sensitivedata/test.rs +++ b/rust/ql/test/library-tests/sensitivedata/test.rs @@ -315,7 +315,7 @@ fn test_private_info( sink(info.financials.credit_card_no.as_str()); // $ sensitive=private sink(info.financials.card_no.as_str()); // $ sensitive=private sink(info.financials.cardNumber.as_str()); // $ sensitive=private - sink(info.financials.card_security_code.as_str()); // $ MISSING: sensitive=private + sink(info.financials.card_security_code.as_str()); // $ sensitive=private sink(info.financials.credit_rating); // $ sensitive=private sink(info.financials.user_ccn.as_str()); // $ sensitive=private sink(info.financials.cvv.as_str()); // $ sensitive=private diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index 80ef76c76ac..f3b979d2e3b 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -106,6 +106,7 @@ module HeuristicNames { // Financial data - such as credit card numbers, salary, bank accounts, and debts "(credit|debit|bank|visa).?(card|num|no|acc(ou)?nt)|(card|acc(ou)?nt).?(no|num|credit)|routing.?num|" + "salary|billing|beneficiary|credit.?(rating|score)|([_-]|\\b)(ccn|cvv|iban)([_-]|\\b)|" + + "security.?code|" + // Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc. // "e(mail|_mail)|" + // this seems too noisy // Health - medical conditions, insurance status, prescription records From 809da0f8e78347cbd3c2e00c70f575044b377aac Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 7 May 2026 10:01:56 +0100 Subject: [PATCH 11/36] Shared: Autoformat. --- .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index f3b979d2e3b..94619488f1a 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -151,8 +151,8 @@ module HeuristicNames { */ string notSensitiveRegexp() { result = - "(?is).*([^\\w$.-]|redact|censor|obfuscate|hash|md5|sha|random|(? Date: Thu, 7 May 2026 10:04:19 +0100 Subject: [PATCH 12/36] Swift: Accept test changes (improvement). --- .../query-tests/Security/CWE-311/CleartextTransmission.expected | 2 ++ .../test/query-tests/Security/CWE-311/SensitiveExprs.expected | 1 + swift/ql/test/query-tests/Security/CWE-311/testSend.swift | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected index c772466344a..7665b72b11a 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextTransmission.expected @@ -64,6 +64,7 @@ nodes | testSend.swift:78:27:78:30 | .CarePlanID | semmle.label | .CarePlanID | | testSend.swift:79:27:79:30 | .BankCardNo | semmle.label | .BankCardNo | | testSend.swift:80:27:80:30 | .MyCreditRating | semmle.label | .MyCreditRating | +| testSend.swift:81:27:81:30 | .OneTimeCode | semmle.label | .OneTimeCode | | testSend.swift:86:7:86:7 | self | semmle.label | self | | testSend.swift:94:27:94:30 | .password | semmle.label | .password | | testSend.swift:94:27:94:39 | .value | semmle.label | .value | @@ -118,6 +119,7 @@ subpaths | testSend.swift:78:27:78:30 | .CarePlanID | testSend.swift:78:27:78:30 | .CarePlanID | testSend.swift:78:27:78:30 | .CarePlanID | This operation transmits '.CarePlanID', which may contain unencrypted sensitive data from $@. | testSend.swift:78:27:78:30 | .CarePlanID | .CarePlanID | | testSend.swift:79:27:79:30 | .BankCardNo | testSend.swift:79:27:79:30 | .BankCardNo | testSend.swift:79:27:79:30 | .BankCardNo | This operation transmits '.BankCardNo', which may contain unencrypted sensitive data from $@. | testSend.swift:79:27:79:30 | .BankCardNo | .BankCardNo | | testSend.swift:80:27:80:30 | .MyCreditRating | testSend.swift:80:27:80:30 | .MyCreditRating | testSend.swift:80:27:80:30 | .MyCreditRating | This operation transmits '.MyCreditRating', which may contain unencrypted sensitive data from $@. | testSend.swift:80:27:80:30 | .MyCreditRating | .MyCreditRating | +| testSend.swift:81:27:81:30 | .OneTimeCode | testSend.swift:81:27:81:30 | .OneTimeCode | testSend.swift:81:27:81:30 | .OneTimeCode | This operation transmits '.OneTimeCode', which may contain unencrypted sensitive data from $@. | testSend.swift:81:27:81:30 | .OneTimeCode | .OneTimeCode | | testSend.swift:94:27:94:39 | .value | testSend.swift:94:27:94:30 | .password | testSend.swift:94:27:94:39 | .value | This operation transmits '.value', which may contain unencrypted sensitive data from $@. | testSend.swift:94:27:94:30 | .password | .password | | testURL.swift:39:18:39:50 | ... .+(_:_:) ... | testURL.swift:39:50:39:50 | passwd | testURL.swift:39:18:39:50 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:39:50:39:50 | passwd | passwd | | testURL.swift:41:18:41:51 | ... .+(_:_:) ... | testURL.swift:41:51:41:51 | account_no | testURL.swift:41:18:41:51 | ... .+(_:_:) ... | This operation transmits '... .+(_:_:) ...', which may contain unencrypted sensitive data from $@. | testURL.swift:41:51:41:51 | account_no | account_no | diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected index c4ff7f42b2e..62fc29a9a58 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected +++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected @@ -170,6 +170,7 @@ | testSend.swift:78:27:78:30 | .CarePlanID | label:CarePlanID, type:private information | | testSend.swift:79:27:79:30 | .BankCardNo | label:BankCardNo, type:private information | | testSend.swift:80:27:80:30 | .MyCreditRating | label:MyCreditRating, type:private information | +| testSend.swift:81:27:81:30 | .OneTimeCode | label:OneTimeCode, type:credential | | testSend.swift:94:27:94:30 | .password | label:password, type:password | | testURL.swift:39:50:39:50 | passwd | label:passwd, type:password | | testURL.swift:41:51:41:51 | account_no | label:account_no, type:private information | diff --git a/swift/ql/test/query-tests/Security/CWE-311/testSend.swift b/swift/ql/test/query-tests/Security/CWE-311/testSend.swift index 8acb83e51c1..bea4dfa16b6 100644 --- a/swift/ql/test/query-tests/Security/CWE-311/testSend.swift +++ b/swift/ql/test/query-tests/Security/CWE-311/testSend.swift @@ -78,7 +78,7 @@ func test2(password : String, license_key: String, ms: MyStruct, connection : NW connection.send(content: ms.CarePlanID, completion: .idempotent) // BAD connection.send(content: ms.BankCardNo, completion: .idempotent) // BAD connection.send(content: ms.MyCreditRating, completion: .idempotent) // BAD - connection.send(content: ms.OneTimeCode, completion: .idempotent) // BAD [NOT DETECTED] + connection.send(content: ms.OneTimeCode, completion: .idempotent) // BAD } struct MyOuter { From ea711b032bc400b7f299459ebfa237eb6c23d112 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 7 May 2026 10:12:35 +0100 Subject: [PATCH 13/36] Javascript: Accept test changes (regression). --- .../Security/CWE-312/CleartextLogging.expected | 12 ++++++++++++ .../test/query-tests/Security/CWE-312/passwords.js | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected b/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected index af9e0f485c2..77eefa87c2b 100644 --- a/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected +++ b/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected @@ -9,6 +9,9 @@ | passwords.js:16:17:16:38 | `${name ... sword}` | passwords.js:16:29:16:36 | password | passwords.js:16:17:16:38 | `${name ... sword}` | This logs sensitive data returned by $@ as clear text. | passwords.js:16:29:16:36 | password | an access to password | | passwords.js:21:17:21:20 | obj1 | passwords.js:19:19:19:19 | x | passwords.js:21:17:21:20 | obj1 | This logs sensitive data returned by $@ as clear text. | passwords.js:19:19:19:19 | x | an access to password | | passwords.js:26:17:26:20 | obj2 | passwords.js:24:12:24:19 | password | passwords.js:26:17:26:20 | obj2 | This logs sensitive data returned by $@ as clear text. | passwords.js:24:12:24:19 | password | an access to password | +| passwords.js:41:17:41:37 | {passwo ... pt(pw)} | passwords.js:41:28:41:36 | crypt(pw) | passwords.js:41:17:41:37 | {passwo ... pt(pw)} | This logs sensitive data returned by $@ as clear text. | passwords.js:41:28:41:36 | crypt(pw) | an access to password | +| passwords.js:43:17:43:40 | actuall ... assword | passwords.js:43:17:43:40 | actuall ... assword | passwords.js:43:17:43:40 | actuall ... assword | This logs sensitive data returned by $@ as clear text. | passwords.js:43:17:43:40 | actuall ... assword | an access to actually_secure_password | +| passwords.js:47:17:47:21 | user1 | passwords.js:46:30:46:32 | x() | passwords.js:47:17:47:21 | user1 | This logs sensitive data returned by $@ as clear text. | passwords.js:46:30:46:32 | x() | an access to crypted_password | | passwords.js:78:17:78:38 | temp.en ... assword | passwords.js:77:37:77:53 | req.body.password | passwords.js:78:17:78:38 | temp.en ... assword | This logs sensitive data returned by $@ as clear text. | passwords.js:77:37:77:53 | req.body.password | an access to password | | passwords.js:81:17:81:31 | `pw: ${secret}` | passwords.js:80:18:80:25 | password | passwords.js:81:17:81:31 | `pw: ${secret}` | This logs sensitive data returned by $@ as clear text. | passwords.js:80:18:80:25 | password | an access to password | | passwords.js:93:21:93:46 | "Passwo ... assword | passwords.js:93:39:93:46 | password | passwords.js:93:21:93:46 | "Passwo ... assword | This logs sensitive data returned by $@ as clear text. | passwords.js:93:39:93:46 | password | an access to password | @@ -52,6 +55,9 @@ edges | passwords.js:23:9:23:12 | obj2 [x] | passwords.js:26:17:26:20 | obj2 | provenance | | | passwords.js:23:16:25:5 | {\\n ... ]\\n } [x] | passwords.js:23:9:23:12 | obj2 [x] | provenance | | | passwords.js:24:12:24:19 | password | passwords.js:23:16:25:5 | {\\n ... ]\\n } [x] | provenance | | +| passwords.js:41:28:41:36 | crypt(pw) | passwords.js:41:17:41:37 | {passwo ... pt(pw)} | provenance | | +| passwords.js:46:5:46:9 | [post update] user1 [crypted_password] | passwords.js:47:17:47:21 | user1 | provenance | | +| passwords.js:46:30:46:32 | x() | passwords.js:46:5:46:9 | [post update] user1 [crypted_password] | provenance | | | passwords.js:77:9:77:12 | temp [encryptedPassword] | passwords.js:78:17:78:20 | temp [encryptedPassword] | provenance | | | passwords.js:77:16:77:55 | { encry ... sword } [encryptedPassword] | passwords.js:77:9:77:12 | temp [encryptedPassword] | provenance | | | passwords.js:77:37:77:53 | req.body.password | passwords.js:77:16:77:55 | { encry ... sword } [encryptedPassword] | provenance | | @@ -139,6 +145,12 @@ nodes | passwords.js:23:16:25:5 | {\\n ... ]\\n } [x] | semmle.label | {\\n ... ]\\n } [x] | | passwords.js:24:12:24:19 | password | semmle.label | password | | passwords.js:26:17:26:20 | obj2 | semmle.label | obj2 | +| passwords.js:41:17:41:37 | {passwo ... pt(pw)} | semmle.label | {passwo ... pt(pw)} | +| passwords.js:41:28:41:36 | crypt(pw) | semmle.label | crypt(pw) | +| passwords.js:43:17:43:40 | actuall ... assword | semmle.label | actuall ... assword | +| passwords.js:46:5:46:9 | [post update] user1 [crypted_password] | semmle.label | [post update] user1 [crypted_password] | +| passwords.js:46:30:46:32 | x() | semmle.label | x() | +| passwords.js:47:17:47:21 | user1 | semmle.label | user1 | | passwords.js:77:9:77:12 | temp [encryptedPassword] | semmle.label | temp [encryptedPassword] | | passwords.js:77:16:77:55 | { encry ... sword } [encryptedPassword] | semmle.label | { encry ... sword } [encryptedPassword] | | passwords.js:77:37:77:53 | req.body.password | semmle.label | req.body.password | diff --git a/javascript/ql/test/query-tests/Security/CWE-312/passwords.js b/javascript/ql/test/query-tests/Security/CWE-312/passwords.js index 47304946e39..ed1c9785f23 100644 --- a/javascript/ql/test/query-tests/Security/CWE-312/passwords.js +++ b/javascript/ql/test/query-tests/Security/CWE-312/passwords.js @@ -38,13 +38,13 @@ console.log(login.wrappedJSObject.encryptedPassword); console.log(HTML5QQ.encodedPassword); - console.log({password: crypt(pw)}); + console.log({password: crypt(pw)}); // $ SPURIOUS: Alert[js/clear-text-logging] var actually_secure_password = crypt(password); - console.log(actually_secure_password); + console.log(actually_secure_password); // $ SPURIOUS: Alert[js/clear-text-logging] var user1 = {}; - user1.crypted_password = x(); - console.log(user1); + user1.crypted_password = x(); // $ SPURIOUS: Source[js/clear-text-logging] + console.log(user1); // $ SPURIOUS: Alert[js/clear-text-logging] var user2 = {}; user2.password = hash(); From 1c704a091296094780246ff83a7c5389c8f9630a Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 7 May 2026 10:28:19 +0100 Subject: [PATCH 14/36] Python: Accept test changes (improvement). --- .../CWE-312-CleartextLogging/CleartextLogging.expected | 8 ++++++++ .../query-tests/Security/CWE-312-CleartextLogging/test.py | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected index dca1a33e73a..7cb9e015190 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/CleartextLogging.expected @@ -10,6 +10,8 @@ edges | test.py:48:14:48:35 | ControlFlowNode for social_security_number | test.py:49:15:49:36 | ControlFlowNode for social_security_number | provenance | | | test.py:48:38:48:40 | ControlFlowNode for ssn | test.py:50:15:50:17 | ControlFlowNode for ssn | provenance | | | test.py:48:54:48:63 | ControlFlowNode for passportNo | test.py:52:15:52:24 | ControlFlowNode for passportNo | provenance | | +| test.py:54:14:54:22 | ControlFlowNode for post_code | test.py:55:15:55:23 | ControlFlowNode for post_code | provenance | | +| test.py:54:25:54:31 | ControlFlowNode for zipCode | test.py:56:15:56:21 | ControlFlowNode for zipCode | provenance | | | test.py:54:34:54:45 | ControlFlowNode for home_address | test.py:57:15:57:26 | ControlFlowNode for home_address | provenance | | | test.py:59:14:59:26 | ControlFlowNode for user_latitude | test.py:60:15:60:27 | ControlFlowNode for user_latitude | provenance | | | test.py:59:29:59:42 | ControlFlowNode for user_longitude | test.py:61:15:61:28 | ControlFlowNode for user_longitude | provenance | | @@ -42,7 +44,11 @@ nodes | test.py:49:15:49:36 | ControlFlowNode for social_security_number | semmle.label | ControlFlowNode for social_security_number | | test.py:50:15:50:17 | ControlFlowNode for ssn | semmle.label | ControlFlowNode for ssn | | test.py:52:15:52:24 | ControlFlowNode for passportNo | semmle.label | ControlFlowNode for passportNo | +| test.py:54:14:54:22 | ControlFlowNode for post_code | semmle.label | ControlFlowNode for post_code | +| test.py:54:25:54:31 | ControlFlowNode for zipCode | semmle.label | ControlFlowNode for zipCode | | test.py:54:34:54:45 | ControlFlowNode for home_address | semmle.label | ControlFlowNode for home_address | +| test.py:55:15:55:23 | ControlFlowNode for post_code | semmle.label | ControlFlowNode for post_code | +| test.py:56:15:56:21 | ControlFlowNode for zipCode | semmle.label | ControlFlowNode for zipCode | | test.py:57:15:57:26 | ControlFlowNode for home_address | semmle.label | ControlFlowNode for home_address | | test.py:59:14:59:26 | ControlFlowNode for user_latitude | semmle.label | ControlFlowNode for user_latitude | | test.py:59:29:59:42 | ControlFlowNode for user_longitude | semmle.label | ControlFlowNode for user_longitude | @@ -79,6 +85,8 @@ subpaths | test.py:49:15:49:36 | ControlFlowNode for social_security_number | test.py:48:14:48:35 | ControlFlowNode for social_security_number | test.py:49:15:49:36 | ControlFlowNode for social_security_number | This expression logs $@ as clear text. | test.py:48:14:48:35 | ControlFlowNode for social_security_number | sensitive data (private) | | test.py:50:15:50:17 | ControlFlowNode for ssn | test.py:48:38:48:40 | ControlFlowNode for ssn | test.py:50:15:50:17 | ControlFlowNode for ssn | This expression logs $@ as clear text. | test.py:48:38:48:40 | ControlFlowNode for ssn | sensitive data (private) | | test.py:52:15:52:24 | ControlFlowNode for passportNo | test.py:48:54:48:63 | ControlFlowNode for passportNo | test.py:52:15:52:24 | ControlFlowNode for passportNo | This expression logs $@ as clear text. | test.py:48:54:48:63 | ControlFlowNode for passportNo | sensitive data (private) | +| test.py:55:15:55:23 | ControlFlowNode for post_code | test.py:54:14:54:22 | ControlFlowNode for post_code | test.py:55:15:55:23 | ControlFlowNode for post_code | This expression logs $@ as clear text. | test.py:54:14:54:22 | ControlFlowNode for post_code | sensitive data (private) | +| test.py:56:15:56:21 | ControlFlowNode for zipCode | test.py:54:25:54:31 | ControlFlowNode for zipCode | test.py:56:15:56:21 | ControlFlowNode for zipCode | This expression logs $@ as clear text. | test.py:54:25:54:31 | ControlFlowNode for zipCode | sensitive data (private) | | test.py:57:15:57:26 | ControlFlowNode for home_address | test.py:54:34:54:45 | ControlFlowNode for home_address | test.py:57:15:57:26 | ControlFlowNode for home_address | This expression logs $@ as clear text. | test.py:54:34:54:45 | ControlFlowNode for home_address | sensitive data (private) | | test.py:60:15:60:27 | ControlFlowNode for user_latitude | test.py:59:14:59:26 | ControlFlowNode for user_latitude | test.py:60:15:60:27 | ControlFlowNode for user_latitude | This expression logs $@ as clear text. | test.py:59:14:59:26 | ControlFlowNode for user_latitude | sensitive data (private) | | test.py:61:15:61:28 | ControlFlowNode for user_longitude | test.py:59:29:59:42 | ControlFlowNode for user_longitude | test.py:61:15:61:28 | ControlFlowNode for user_longitude | This expression logs $@ as clear text. | test.py:59:29:59:42 | ControlFlowNode for user_longitude | sensitive data (private) | diff --git a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/test.py b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/test.py index d8d70c56bd5..ff01680ed81 100644 --- a/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/test.py +++ b/python/ql/test/query-tests/Security/CWE-312-CleartextLogging/test.py @@ -52,8 +52,8 @@ def log_private(): print(passportNo) # NOT OK def log2(post_code, zipCode, home_address): - print(post_code) # NOT OK, but NOT FOUND - "code" is treated as encrypted and thus not sensitive - print(zipCode) # NOT OK, but NOT FOUND - "code" is treated as encrypted and thus not sensitive + print(post_code) # NOT OK + print(zipCode) # NOT OK print(home_address) # NOT OK def log3(user_latitude, user_longitude): From df37b500516e7f633f0b640a12924bd35e34b2bf Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 7 May 2026 10:35:04 +0100 Subject: [PATCH 15/36] Shared: Small adjustment to the encrypt not-sensitive regex. --- .../Security/CWE-312/CleartextLogging.expected | 12 ------------ .../test/query-tests/Security/CWE-312/passwords.js | 8 ++++---- .../concepts/internal/SensitiveDataHeuristics.qll | 3 ++- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected b/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected index 77eefa87c2b..af9e0f485c2 100644 --- a/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected +++ b/javascript/ql/test/query-tests/Security/CWE-312/CleartextLogging.expected @@ -9,9 +9,6 @@ | passwords.js:16:17:16:38 | `${name ... sword}` | passwords.js:16:29:16:36 | password | passwords.js:16:17:16:38 | `${name ... sword}` | This logs sensitive data returned by $@ as clear text. | passwords.js:16:29:16:36 | password | an access to password | | passwords.js:21:17:21:20 | obj1 | passwords.js:19:19:19:19 | x | passwords.js:21:17:21:20 | obj1 | This logs sensitive data returned by $@ as clear text. | passwords.js:19:19:19:19 | x | an access to password | | passwords.js:26:17:26:20 | obj2 | passwords.js:24:12:24:19 | password | passwords.js:26:17:26:20 | obj2 | This logs sensitive data returned by $@ as clear text. | passwords.js:24:12:24:19 | password | an access to password | -| passwords.js:41:17:41:37 | {passwo ... pt(pw)} | passwords.js:41:28:41:36 | crypt(pw) | passwords.js:41:17:41:37 | {passwo ... pt(pw)} | This logs sensitive data returned by $@ as clear text. | passwords.js:41:28:41:36 | crypt(pw) | an access to password | -| passwords.js:43:17:43:40 | actuall ... assword | passwords.js:43:17:43:40 | actuall ... assword | passwords.js:43:17:43:40 | actuall ... assword | This logs sensitive data returned by $@ as clear text. | passwords.js:43:17:43:40 | actuall ... assword | an access to actually_secure_password | -| passwords.js:47:17:47:21 | user1 | passwords.js:46:30:46:32 | x() | passwords.js:47:17:47:21 | user1 | This logs sensitive data returned by $@ as clear text. | passwords.js:46:30:46:32 | x() | an access to crypted_password | | passwords.js:78:17:78:38 | temp.en ... assword | passwords.js:77:37:77:53 | req.body.password | passwords.js:78:17:78:38 | temp.en ... assword | This logs sensitive data returned by $@ as clear text. | passwords.js:77:37:77:53 | req.body.password | an access to password | | passwords.js:81:17:81:31 | `pw: ${secret}` | passwords.js:80:18:80:25 | password | passwords.js:81:17:81:31 | `pw: ${secret}` | This logs sensitive data returned by $@ as clear text. | passwords.js:80:18:80:25 | password | an access to password | | passwords.js:93:21:93:46 | "Passwo ... assword | passwords.js:93:39:93:46 | password | passwords.js:93:21:93:46 | "Passwo ... assword | This logs sensitive data returned by $@ as clear text. | passwords.js:93:39:93:46 | password | an access to password | @@ -55,9 +52,6 @@ edges | passwords.js:23:9:23:12 | obj2 [x] | passwords.js:26:17:26:20 | obj2 | provenance | | | passwords.js:23:16:25:5 | {\\n ... ]\\n } [x] | passwords.js:23:9:23:12 | obj2 [x] | provenance | | | passwords.js:24:12:24:19 | password | passwords.js:23:16:25:5 | {\\n ... ]\\n } [x] | provenance | | -| passwords.js:41:28:41:36 | crypt(pw) | passwords.js:41:17:41:37 | {passwo ... pt(pw)} | provenance | | -| passwords.js:46:5:46:9 | [post update] user1 [crypted_password] | passwords.js:47:17:47:21 | user1 | provenance | | -| passwords.js:46:30:46:32 | x() | passwords.js:46:5:46:9 | [post update] user1 [crypted_password] | provenance | | | passwords.js:77:9:77:12 | temp [encryptedPassword] | passwords.js:78:17:78:20 | temp [encryptedPassword] | provenance | | | passwords.js:77:16:77:55 | { encry ... sword } [encryptedPassword] | passwords.js:77:9:77:12 | temp [encryptedPassword] | provenance | | | passwords.js:77:37:77:53 | req.body.password | passwords.js:77:16:77:55 | { encry ... sword } [encryptedPassword] | provenance | | @@ -145,12 +139,6 @@ nodes | passwords.js:23:16:25:5 | {\\n ... ]\\n } [x] | semmle.label | {\\n ... ]\\n } [x] | | passwords.js:24:12:24:19 | password | semmle.label | password | | passwords.js:26:17:26:20 | obj2 | semmle.label | obj2 | -| passwords.js:41:17:41:37 | {passwo ... pt(pw)} | semmle.label | {passwo ... pt(pw)} | -| passwords.js:41:28:41:36 | crypt(pw) | semmle.label | crypt(pw) | -| passwords.js:43:17:43:40 | actuall ... assword | semmle.label | actuall ... assword | -| passwords.js:46:5:46:9 | [post update] user1 [crypted_password] | semmle.label | [post update] user1 [crypted_password] | -| passwords.js:46:30:46:32 | x() | semmle.label | x() | -| passwords.js:47:17:47:21 | user1 | semmle.label | user1 | | passwords.js:77:9:77:12 | temp [encryptedPassword] | semmle.label | temp [encryptedPassword] | | passwords.js:77:16:77:55 | { encry ... sword } [encryptedPassword] | semmle.label | { encry ... sword } [encryptedPassword] | | passwords.js:77:37:77:53 | req.body.password | semmle.label | req.body.password | diff --git a/javascript/ql/test/query-tests/Security/CWE-312/passwords.js b/javascript/ql/test/query-tests/Security/CWE-312/passwords.js index ed1c9785f23..47304946e39 100644 --- a/javascript/ql/test/query-tests/Security/CWE-312/passwords.js +++ b/javascript/ql/test/query-tests/Security/CWE-312/passwords.js @@ -38,13 +38,13 @@ console.log(login.wrappedJSObject.encryptedPassword); console.log(HTML5QQ.encodedPassword); - console.log({password: crypt(pw)}); // $ SPURIOUS: Alert[js/clear-text-logging] + console.log({password: crypt(pw)}); var actually_secure_password = crypt(password); - console.log(actually_secure_password); // $ SPURIOUS: Alert[js/clear-text-logging] + console.log(actually_secure_password); var user1 = {}; - user1.crypted_password = x(); // $ SPURIOUS: Source[js/clear-text-logging] - console.log(user1); // $ SPURIOUS: Alert[js/clear-text-logging] + user1.crypted_password = x(); + console.log(user1); var user2 = {}; user2.password = hash(); diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index 94619488f1a..13861dfdd25 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -151,7 +151,8 @@ module HeuristicNames { */ string notSensitiveRegexp() { result = - "(?is).*([^\\w$.-]|redact|censor|obfuscate|hash|md5|sha|random|(? Date: Thu, 7 May 2026 17:21:13 +0100 Subject: [PATCH 16/36] Shared: Autoformat. --- .../codeql/concepts/internal/SensitiveDataHeuristics.qll | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll index 13861dfdd25..b2bda909e3b 100644 --- a/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll +++ b/shared/concepts/codeql/concepts/internal/SensitiveDataHeuristics.qll @@ -151,8 +151,7 @@ module HeuristicNames { */ string notSensitiveRegexp() { result = - "(?is).*([^\\w$.-]|redact|censor|obfuscate|hash|md5|sha|random|(? Date: Mon, 4 May 2026 13:50:49 +0200 Subject: [PATCH 17/36] C#: Add Increment/Decrement instance operator test example and update test expected output. --- .../operators/Operators3.expected | 2 +- .../operators/Operators4.expected | 2 +- .../operators/Operators5.expected | 30 +- .../library-tests/operators/PrintAst.expected | 345 ++++++++++-------- .../test/library-tests/operators/operators.cs | 75 ++-- 5 files changed, 261 insertions(+), 193 deletions(-) diff --git a/csharp/ql/test/library-tests/operators/Operators3.expected b/csharp/ql/test/library-tests/operators/Operators3.expected index e81aec79ba1..bda7edb99ba 100644 --- a/csharp/ql/test/library-tests/operators/Operators3.expected +++ b/csharp/ql/test/library-tests/operators/Operators3.expected @@ -1 +1 @@ -| operators.cs:96:32:96:39 | implicit conversion | +| operators.cs:118:36:118:43 | implicit conversion | diff --git a/csharp/ql/test/library-tests/operators/Operators4.expected b/csharp/ql/test/library-tests/operators/Operators4.expected index 49db993c093..bee27656f26 100644 --- a/csharp/ql/test/library-tests/operators/Operators4.expected +++ b/csharp/ql/test/library-tests/operators/Operators4.expected @@ -1 +1 @@ -| operators.cs:101:32:101:39 | explicit conversion | +| operators.cs:123:36:123:43 | explicit conversion | diff --git a/csharp/ql/test/library-tests/operators/Operators5.expected b/csharp/ql/test/library-tests/operators/Operators5.expected index 8e506e5119d..900b5170c34 100644 --- a/csharp/ql/test/library-tests/operators/Operators5.expected +++ b/csharp/ql/test/library-tests/operators/Operators5.expected @@ -1,15 +1,15 @@ -| operators.cs:23:30:23:31 | += | operators.cs:61:13:61:22 | ... += ... | -| operators.cs:31:38:31:39 | checked += | operators.cs:77:17:77:26 | ... += ... | -| operators.cs:33:38:33:39 | checked -= | operators.cs:78:17:78:26 | ... -= ... | -| operators.cs:34:30:34:31 | -= | operators.cs:64:13:64:22 | ... -= ... | -| operators.cs:36:38:36:39 | checked *= | operators.cs:79:17:79:26 | ... *= ... | -| operators.cs:37:30:37:31 | *= | operators.cs:65:13:65:22 | ... *= ... | -| operators.cs:39:38:39:39 | checked /= | operators.cs:80:17:80:26 | ... /= ... | -| operators.cs:40:30:40:31 | /= | operators.cs:66:13:66:22 | ... /= ... | -| operators.cs:42:30:42:31 | %= | operators.cs:67:13:67:22 | ... %= ... | -| operators.cs:43:30:43:31 | &= | operators.cs:68:13:68:22 | ... &= ... | -| operators.cs:44:30:44:31 | \|= | operators.cs:69:13:69:22 | ... \|= ... | -| operators.cs:45:30:45:31 | ^= | operators.cs:70:13:70:22 | ... ^= ... | -| operators.cs:46:30:46:32 | <<= | operators.cs:71:13:71:23 | ... <<= ... | -| operators.cs:47:30:47:32 | >>= | operators.cs:72:13:72:23 | ... >>= ... | -| operators.cs:48:30:48:33 | >>>= | operators.cs:73:13:73:24 | ... >>>= ... | +| operators.cs:23:30:23:31 | += | operators.cs:70:13:70:22 | ... += ... | +| operators.cs:31:38:31:39 | checked += | operators.cs:86:17:86:26 | ... += ... | +| operators.cs:33:38:33:39 | checked -= | operators.cs:87:17:87:26 | ... -= ... | +| operators.cs:34:30:34:31 | -= | operators.cs:73:13:73:22 | ... -= ... | +| operators.cs:36:38:36:39 | checked *= | operators.cs:88:17:88:26 | ... *= ... | +| operators.cs:37:30:37:31 | *= | operators.cs:74:13:74:22 | ... *= ... | +| operators.cs:39:38:39:39 | checked /= | operators.cs:89:17:89:26 | ... /= ... | +| operators.cs:40:30:40:31 | /= | operators.cs:75:13:75:22 | ... /= ... | +| operators.cs:42:30:42:31 | %= | operators.cs:76:13:76:22 | ... %= ... | +| operators.cs:43:30:43:31 | &= | operators.cs:77:13:77:22 | ... &= ... | +| operators.cs:44:30:44:31 | \|= | operators.cs:78:13:78:22 | ... \|= ... | +| operators.cs:45:30:45:31 | ^= | operators.cs:79:13:79:22 | ... ^= ... | +| operators.cs:46:30:46:32 | <<= | operators.cs:80:13:80:23 | ... <<= ... | +| operators.cs:47:30:47:32 | >>= | operators.cs:81:13:81:23 | ... >>= ... | +| operators.cs:48:30:48:33 | >>>= | operators.cs:82:13:82:24 | ... >>>= ... | diff --git a/csharp/ql/test/library-tests/operators/PrintAst.expected b/csharp/ql/test/library-tests/operators/PrintAst.expected index 8ea38d79b14..1c335faddb0 100644 --- a/csharp/ql/test/library-tests/operators/PrintAst.expected +++ b/csharp/ql/test/library-tests/operators/PrintAst.expected @@ -181,159 +181,204 @@ operators.cs: # 48| 0: [Parameter] n # 48| -1: [TypeMention] IntVector # 48| 4: [BlockStmt] {...} -# 51| 2: [Class] TestOperator -# 53| 6: [Method] Main -# 53| -1: [TypeMention] Void +# 51| 2: [Class] C +# 54| 6: [???] checked ++= +# 54| -1: [TypeMention] Void # 54| 4: [BlockStmt] {...} -# 55| 0: [LocalVariableDeclStmt] ... ...; -# 55| 0: [LocalVariableDeclAndInitExpr] IntVector iv1 = ... -# 55| -1: [TypeMention] IntVector -# 55| 0: [LocalVariableAccess] access to local variable iv1 -# 55| 1: [ObjectCreation] object creation of type IntVector -# 55| -1: [TypeMention] IntVector -# 55| 0: [IntLiteral] 4 -# 56| 1: [LocalVariableDeclStmt] ... ...; -# 56| 0: [LocalVariableDeclExpr] IntVector iv2 -# 56| 0: [TypeMention] IntVector -# 57| 2: [ExprStmt] ...; -# 57| 0: [AssignExpr] ... = ... -# 57| 0: [LocalVariableAccess] access to local variable iv2 -# 57| 1: [OperatorCall] call to operator ++ -# 57| 0: [LocalVariableAccess] access to local variable iv1 -# 58| 3: [ExprStmt] ...; -# 58| 0: [AssignExpr] ... = ... -# 58| 0: [LocalVariableAccess] access to local variable iv2 -# 58| 1: [OperatorCall] call to operator ++ -# 58| 0: [LocalVariableAccess] access to local variable iv1 -# 60| 4: [LocalVariableDeclStmt] ... ...; -# 60| 0: [LocalVariableDeclAndInitExpr] IntVector iv3 = ... -# 60| -1: [TypeMention] IntVector -# 60| 0: [LocalVariableAccess] access to local variable iv3 -# 60| 1: [ObjectCreation] object creation of type IntVector -# 60| -1: [TypeMention] IntVector -# 60| 0: [IntLiteral] 4 -# 61| 5: [ExprStmt] ...; -# 61| 0: [AssignAddExpr] ... += ... -# 61| 0: [LocalVariableAccess] access to local variable iv3 -# 61| 1: [LocalVariableAccess] access to local variable iv2 -# 64| 6: [ExprStmt] ...; -# 64| 0: [AssignSubExpr] ... -= ... -# 64| 0: [LocalVariableAccess] access to local variable iv3 -# 64| 1: [LocalVariableAccess] access to local variable iv2 -# 65| 7: [ExprStmt] ...; -# 65| 0: [AssignMulExpr] ... *= ... -# 65| 0: [LocalVariableAccess] access to local variable iv3 -# 65| 1: [LocalVariableAccess] access to local variable iv2 -# 66| 8: [ExprStmt] ...; -# 66| 0: [AssignDivExpr] ... /= ... -# 66| 0: [LocalVariableAccess] access to local variable iv3 -# 66| 1: [LocalVariableAccess] access to local variable iv2 -# 67| 9: [ExprStmt] ...; -# 67| 0: [AssignRemExpr] ... %= ... -# 67| 0: [LocalVariableAccess] access to local variable iv3 -# 67| 1: [LocalVariableAccess] access to local variable iv2 -# 68| 10: [ExprStmt] ...; -# 68| 0: [AssignAndExpr] ... &= ... -# 68| 0: [LocalVariableAccess] access to local variable iv3 -# 68| 1: [LocalVariableAccess] access to local variable iv2 -# 69| 11: [ExprStmt] ...; -# 69| 0: [AssignOrExpr] ... |= ... +# 55| 7: [???] ++= +# 55| -1: [TypeMention] Void +# 55| 4: [BlockStmt] {...} +# 56| 8: [???] checked --= +# 56| -1: [TypeMention] Void +# 56| 4: [BlockStmt] {...} +# 57| 9: [???] --= +# 57| -1: [TypeMention] Void +# 57| 4: [BlockStmt] {...} +# 60| 3: [Class] TestOperator +# 62| 6: [Method] Main +# 62| -1: [TypeMention] Void +# 63| 4: [BlockStmt] {...} +# 64| 0: [LocalVariableDeclStmt] ... ...; +# 64| 0: [LocalVariableDeclAndInitExpr] IntVector iv1 = ... +# 64| -1: [TypeMention] IntVector +# 64| 0: [LocalVariableAccess] access to local variable iv1 +# 64| 1: [ObjectCreation] object creation of type IntVector +# 64| -1: [TypeMention] IntVector +# 64| 0: [IntLiteral] 4 +# 65| 1: [LocalVariableDeclStmt] ... ...; +# 65| 0: [LocalVariableDeclExpr] IntVector iv2 +# 65| 0: [TypeMention] IntVector +# 66| 2: [ExprStmt] ...; +# 66| 0: [AssignExpr] ... = ... +# 66| 0: [LocalVariableAccess] access to local variable iv2 +# 66| 1: [OperatorCall] call to operator ++ +# 66| 0: [LocalVariableAccess] access to local variable iv1 +# 67| 3: [ExprStmt] ...; +# 67| 0: [AssignExpr] ... = ... +# 67| 0: [LocalVariableAccess] access to local variable iv2 +# 67| 1: [OperatorCall] call to operator ++ +# 67| 0: [LocalVariableAccess] access to local variable iv1 +# 69| 4: [LocalVariableDeclStmt] ... ...; +# 69| 0: [LocalVariableDeclAndInitExpr] IntVector iv3 = ... +# 69| -1: [TypeMention] IntVector # 69| 0: [LocalVariableAccess] access to local variable iv3 -# 69| 1: [LocalVariableAccess] access to local variable iv2 -# 70| 12: [ExprStmt] ...; -# 70| 0: [AssignXorExpr] ... ^= ... +# 69| 1: [ObjectCreation] object creation of type IntVector +# 69| -1: [TypeMention] IntVector +# 69| 0: [IntLiteral] 4 +# 70| 5: [ExprStmt] ...; +# 70| 0: [AssignAddExpr] ... += ... # 70| 0: [LocalVariableAccess] access to local variable iv3 # 70| 1: [LocalVariableAccess] access to local variable iv2 -# 71| 13: [ExprStmt] ...; -# 71| 0: [AssignLeftShiftExpr] ... <<= ... -# 71| 0: [LocalVariableAccess] access to local variable iv3 -# 71| 1: [LocalVariableAccess] access to local variable iv2 -# 72| 14: [ExprStmt] ...; -# 72| 0: [AssignRightShiftExpr] ... >>= ... -# 72| 0: [LocalVariableAccess] access to local variable iv3 -# 72| 1: [LocalVariableAccess] access to local variable iv2 -# 73| 15: [ExprStmt] ...; -# 73| 0: [AssignUnsignedRightShiftExpr] ... >>>= ... +# 73| 6: [ExprStmt] ...; +# 73| 0: [AssignSubExpr] ... -= ... # 73| 0: [LocalVariableAccess] access to local variable iv3 # 73| 1: [LocalVariableAccess] access to local variable iv2 -# 75| 16: [CheckedStmt] checked {...} -# 76| 0: [BlockStmt] {...} -# 77| 0: [ExprStmt] ...; -# 77| 0: [AssignAddExpr] ... += ... -# 77| 0: [LocalVariableAccess] access to local variable iv3 -# 77| 1: [LocalVariableAccess] access to local variable iv2 -# 78| 1: [ExprStmt] ...; -# 78| 0: [AssignSubExpr] ... -= ... -# 78| 0: [LocalVariableAccess] access to local variable iv3 -# 78| 1: [LocalVariableAccess] access to local variable iv2 -# 79| 2: [ExprStmt] ...; -# 79| 0: [AssignMulExpr] ... *= ... -# 79| 0: [LocalVariableAccess] access to local variable iv3 -# 79| 1: [LocalVariableAccess] access to local variable iv2 -# 80| 3: [ExprStmt] ...; -# 80| 0: [AssignDivExpr] ... /= ... -# 80| 0: [LocalVariableAccess] access to local variable iv3 -# 80| 1: [LocalVariableAccess] access to local variable iv2 -# 85| 3: [Struct] Digit -# 87| 6: [Field] value -# 87| -1: [TypeMention] byte -# 89| 7: [InstanceConstructor] Digit -#-----| 2: (Parameters) -# 89| 0: [Parameter] value -# 89| -1: [TypeMention] byte -# 90| 4: [BlockStmt] {...} -# 91| 0: [IfStmt] if (...) ... -# 91| 0: [LogicalOrExpr] ... || ... -# 91| 0: [LTExpr] ... < ... -# 91| 0: [CastExpr] (...) ... -# 91| 1: [ParameterAccess] access to parameter value -# 91| 1: [IntLiteral] 0 -# 91| 1: [GTExpr] ... > ... -# 91| 0: [CastExpr] (...) ... -# 91| 1: [ParameterAccess] access to parameter value -# 91| 1: [IntLiteral] 9 -# 92| 1: [ThrowStmt] throw ...; -# 92| 0: [ObjectCreation] object creation of type ArgumentException -# 92| 0: [TypeMention] ArgumentException -# 93| 1: [ExprStmt] ...; -# 93| 0: [AssignExpr] ... = ... -# 93| 0: [FieldAccess] access to field value -# 93| -1: [ThisAccess] this access -# 93| 1: [ParameterAccess] access to parameter value -# 96| 8: [ImplicitConversionOperator] implicit conversion -# 96| -1: [TypeMention] byte -#-----| 2: (Parameters) -# 96| 0: [Parameter] d -# 96| -1: [TypeMention] Digit -# 97| 4: [BlockStmt] {...} -# 98| 0: [ReturnStmt] return ...; -# 98| 0: [FieldAccess] access to field value -# 98| -1: [ParameterAccess] access to parameter d -# 101| 9: [ExplicitConversionOperator] explicit conversion -# 101| -1: [TypeMention] Digit -#-----| 2: (Parameters) -# 101| 0: [Parameter] b -# 101| -1: [TypeMention] byte -# 102| 4: [BlockStmt] {...} -# 103| 0: [ReturnStmt] return ...; -# 103| 0: [ObjectCreation] object creation of type Digit -# 103| -1: [TypeMention] Digit -# 103| 0: [ParameterAccess] access to parameter b -# 108| 4: [Class] TestConversionOperator -# 111| 6: [Method] Main -# 111| -1: [TypeMention] Void -# 112| 4: [BlockStmt] {...} -# 113| 0: [LocalVariableDeclStmt] ... ...; -# 113| 0: [LocalVariableDeclAndInitExpr] Digit d = ... -# 113| -1: [TypeMention] Digit -# 113| 0: [LocalVariableAccess] access to local variable d -# 113| 1: [OperatorCall] call to operator explicit conversion -# 113| -1: [TypeMention] Digit -# 113| 0: [CastExpr] (...) ... -# 113| 1: [IntLiteral] 8 -# 114| 1: [LocalVariableDeclStmt] ... ...; -# 114| 0: [LocalVariableDeclAndInitExpr] Byte b = ... -# 114| -1: [TypeMention] byte -# 114| 0: [LocalVariableAccess] access to local variable b -# 114| 1: [OperatorCall] call to operator implicit conversion -# 114| 0: [LocalVariableAccess] access to local variable d +# 74| 7: [ExprStmt] ...; +# 74| 0: [AssignMulExpr] ... *= ... +# 74| 0: [LocalVariableAccess] access to local variable iv3 +# 74| 1: [LocalVariableAccess] access to local variable iv2 +# 75| 8: [ExprStmt] ...; +# 75| 0: [AssignDivExpr] ... /= ... +# 75| 0: [LocalVariableAccess] access to local variable iv3 +# 75| 1: [LocalVariableAccess] access to local variable iv2 +# 76| 9: [ExprStmt] ...; +# 76| 0: [AssignRemExpr] ... %= ... +# 76| 0: [LocalVariableAccess] access to local variable iv3 +# 76| 1: [LocalVariableAccess] access to local variable iv2 +# 77| 10: [ExprStmt] ...; +# 77| 0: [AssignAndExpr] ... &= ... +# 77| 0: [LocalVariableAccess] access to local variable iv3 +# 77| 1: [LocalVariableAccess] access to local variable iv2 +# 78| 11: [ExprStmt] ...; +# 78| 0: [AssignOrExpr] ... |= ... +# 78| 0: [LocalVariableAccess] access to local variable iv3 +# 78| 1: [LocalVariableAccess] access to local variable iv2 +# 79| 12: [ExprStmt] ...; +# 79| 0: [AssignXorExpr] ... ^= ... +# 79| 0: [LocalVariableAccess] access to local variable iv3 +# 79| 1: [LocalVariableAccess] access to local variable iv2 +# 80| 13: [ExprStmt] ...; +# 80| 0: [AssignLeftShiftExpr] ... <<= ... +# 80| 0: [LocalVariableAccess] access to local variable iv3 +# 80| 1: [LocalVariableAccess] access to local variable iv2 +# 81| 14: [ExprStmt] ...; +# 81| 0: [AssignRightShiftExpr] ... >>= ... +# 81| 0: [LocalVariableAccess] access to local variable iv3 +# 81| 1: [LocalVariableAccess] access to local variable iv2 +# 82| 15: [ExprStmt] ...; +# 82| 0: [AssignUnsignedRightShiftExpr] ... >>>= ... +# 82| 0: [LocalVariableAccess] access to local variable iv3 +# 82| 1: [LocalVariableAccess] access to local variable iv2 +# 84| 16: [CheckedStmt] checked {...} +# 85| 0: [BlockStmt] {...} +# 86| 0: [ExprStmt] ...; +# 86| 0: [AssignAddExpr] ... += ... +# 86| 0: [LocalVariableAccess] access to local variable iv3 +# 86| 1: [LocalVariableAccess] access to local variable iv2 +# 87| 1: [ExprStmt] ...; +# 87| 0: [AssignSubExpr] ... -= ... +# 87| 0: [LocalVariableAccess] access to local variable iv3 +# 87| 1: [LocalVariableAccess] access to local variable iv2 +# 88| 2: [ExprStmt] ...; +# 88| 0: [AssignMulExpr] ... *= ... +# 88| 0: [LocalVariableAccess] access to local variable iv3 +# 88| 1: [LocalVariableAccess] access to local variable iv2 +# 89| 3: [ExprStmt] ...; +# 89| 0: [AssignDivExpr] ... /= ... +# 89| 0: [LocalVariableAccess] access to local variable iv3 +# 89| 1: [LocalVariableAccess] access to local variable iv2 +# 92| 17: [LocalVariableDeclStmt] ... ...; +# 92| 0: [LocalVariableDeclAndInitExpr] C c = ... +# 92| -1: [TypeMention] C +# 92| 0: [LocalVariableAccess] access to local variable c +# 92| 1: [ObjectCreation] object creation of type C +# 92| 0: [TypeMention] C +# 93| 18: [ExprStmt] ...; +# 93| 0: [OperatorCall] call to operator ++= +# 93| 0: [LocalVariableAccess] access to local variable c +# 94| 19: [ExprStmt] ...; +# 94| 0: [OperatorCall] call to operator ++= +# 94| 0: [LocalVariableAccess] access to local variable c +# 95| 20: [ExprStmt] ...; +# 95| 0: [OperatorCall] call to operator --= +# 95| 0: [LocalVariableAccess] access to local variable c +# 96| 21: [ExprStmt] ...; +# 96| 0: [OperatorCall] call to operator --= +# 96| 0: [LocalVariableAccess] access to local variable c +# 98| 22: [CheckedStmt] checked {...} +# 99| 0: [BlockStmt] {...} +# 100| 0: [ExprStmt] ...; +# 100| 0: [OperatorCall] call to operator checked ++= +# 100| 0: [LocalVariableAccess] access to local variable c +# 101| 1: [ExprStmt] ...; +# 101| 0: [OperatorCall] call to operator checked ++= +# 101| 0: [LocalVariableAccess] access to local variable c +# 102| 2: [ExprStmt] ...; +# 102| 0: [OperatorCall] call to operator checked --= +# 102| 0: [LocalVariableAccess] access to local variable c +# 103| 3: [ExprStmt] ...; +# 103| 0: [OperatorCall] call to operator checked --= +# 103| 0: [LocalVariableAccess] access to local variable c +# 107| 7: [Struct] Digit +# 109| 6: [Field] value +# 109| -1: [TypeMention] byte +# 111| 7: [InstanceConstructor] Digit +#-----| 2: (Parameters) +# 111| 0: [Parameter] value +# 111| -1: [TypeMention] byte +# 112| 4: [BlockStmt] {...} +# 113| 0: [IfStmt] if (...) ... +# 113| 0: [LogicalOrExpr] ... || ... +# 113| 0: [LTExpr] ... < ... +# 113| 0: [CastExpr] (...) ... +# 113| 1: [ParameterAccess] access to parameter value +# 113| 1: [IntLiteral] 0 +# 113| 1: [GTExpr] ... > ... +# 113| 0: [CastExpr] (...) ... +# 113| 1: [ParameterAccess] access to parameter value +# 113| 1: [IntLiteral] 9 +# 114| 1: [ThrowStmt] throw ...; +# 114| 0: [ObjectCreation] object creation of type ArgumentException +# 114| 0: [TypeMention] ArgumentException +# 115| 1: [ExprStmt] ...; +# 115| 0: [AssignExpr] ... = ... +# 115| 0: [FieldAccess] access to field value +# 115| -1: [ThisAccess] this access +# 115| 1: [ParameterAccess] access to parameter value +# 118| 8: [ImplicitConversionOperator] implicit conversion +# 118| -1: [TypeMention] byte +#-----| 2: (Parameters) +# 118| 0: [Parameter] d +# 118| -1: [TypeMention] Digit +# 119| 4: [BlockStmt] {...} +# 120| 0: [ReturnStmt] return ...; +# 120| 0: [FieldAccess] access to field value +# 120| -1: [ParameterAccess] access to parameter d +# 123| 9: [ExplicitConversionOperator] explicit conversion +# 123| -1: [TypeMention] Digit +#-----| 2: (Parameters) +# 123| 0: [Parameter] b +# 123| -1: [TypeMention] byte +# 124| 4: [BlockStmt] {...} +# 125| 0: [ReturnStmt] return ...; +# 125| 0: [ObjectCreation] object creation of type Digit +# 125| -1: [TypeMention] Digit +# 125| 0: [ParameterAccess] access to parameter b +# 130| 8: [Class] TestConversionOperator +# 133| 6: [Method] Main +# 133| -1: [TypeMention] Void +# 134| 4: [BlockStmt] {...} +# 135| 0: [LocalVariableDeclStmt] ... ...; +# 135| 0: [LocalVariableDeclAndInitExpr] Digit d = ... +# 135| -1: [TypeMention] Digit +# 135| 0: [LocalVariableAccess] access to local variable d +# 135| 1: [OperatorCall] call to operator explicit conversion +# 135| -1: [TypeMention] Digit +# 135| 0: [CastExpr] (...) ... +# 135| 1: [IntLiteral] 8 +# 136| 1: [LocalVariableDeclStmt] ... ...; +# 136| 0: [LocalVariableDeclAndInitExpr] Byte b = ... +# 136| -1: [TypeMention] byte +# 136| 0: [LocalVariableAccess] access to local variable b +# 136| 1: [OperatorCall] call to operator implicit conversion +# 136| 0: [LocalVariableAccess] access to local variable d diff --git a/csharp/ql/test/library-tests/operators/operators.cs b/csharp/ql/test/library-tests/operators/operators.cs index 3ff2fe1a26b..22aee92e36d 100644 --- a/csharp/ql/test/library-tests/operators/operators.cs +++ b/csharp/ql/test/library-tests/operators/operators.cs @@ -48,6 +48,15 @@ namespace Operators public void operator >>>=(IntVector n) { } } + public class C + { + // Unary instance operators. + public void operator checked ++() { } + public void operator ++() { } + public void operator checked --() { } + public void operator --() { } + } + class TestOperator { void Main() @@ -79,41 +88,55 @@ namespace Operators iv3 *= iv2; iv3 /= iv2; } - } - } - public struct Digit - { - byte value; + var c = new C(); + c++; + ++c; + c--; + --c; - public Digit(byte value) - { - if (value < 0 || value > 9) - throw new ArgumentException(); - this.value = value; + checked + { + c++; + ++c; + c--; + --c; + } } - public static implicit operator byte(Digit d) + public struct Digit { - return d.value; + byte value; + + public Digit(byte value) + { + if (value < 0 || value > 9) + throw new ArgumentException(); + this.value = value; + } + + public static implicit operator byte(Digit d) + { + return d.value; + } + + public static explicit operator Digit(byte b) + { + return new Digit(b); + } + } - public static explicit operator Digit(byte b) + class TestConversionOperator { - return new Digit(b); + + void Main() + { + Digit d = (Digit)8; + byte b = d; + } + } } - - class TestConversionOperator - { - - void Main() - { - Digit d = (Digit)8; - byte b = d; - } - - } - } From 3c9d89851d0f6f92e6608c6ec4c270c7041182a9 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 5 May 2026 09:47:55 +0200 Subject: [PATCH 18/36] C#: Adjust the extractor to correctly handle names for user defined increment and decrement operators. --- .../Semmle.Extraction.CSharp.Util/SymbolExtensions.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs index 92d7ecfad6b..50604e2404e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs @@ -52,6 +52,13 @@ namespace Semmle.Extraction.CSharp.Util { "op_False", "false" } }); + /// + /// The operatorname for user-defined increment and decrement operators are "op_IncrementAssignment" and + /// "op_DecrementAssignment" respectively. + /// Thus we need to handle this explicitly to avoid postfixing them with an "=". + /// + private static bool isIncrementOrDecrement(string operatorName) => operatorName == "++" || operatorName == "--"; + /// /// Convert an operator method name in to a symbolic name. /// A return value indicates whether the conversion succeeded. @@ -72,7 +79,7 @@ namespace Semmle.Extraction.CSharp.Util if (match.Success && methodToOperator.TryGetValue($"op_{match.Groups[2]}", out var rawOperatorName)) { var prefix = match.Groups[1].Success ? "checked " : ""; - var postfix = match.Groups[3].Success ? "=" : ""; + var postfix = match.Groups[3].Success && !isIncrementOrDecrement(rawOperatorName) ? "=" : ""; operatorName = $"{prefix}{rawOperatorName}{postfix}"; return true; } From 4ae4d7d78d3ab20525f00518bc806c647fd98724 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 5 May 2026 09:49:41 +0200 Subject: [PATCH 19/36] C#: Update condition for UnaryOperators to also handle user-defined instance increment and decrement operators. --- csharp/ql/lib/semmle/code/csharp/Callable.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll index 9416a7d4d9c..198ad2af180 100644 --- a/csharp/ql/lib/semmle/code/csharp/Callable.qll +++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll @@ -613,6 +613,9 @@ class UnaryOperator extends Operator { this.getNumberOfParameters() = 1 and not this instanceof ConversionOperator and not this instanceof CompoundAssignmentOperator + or + // Instance increment and decrement operators don't have a parameter (only a qualifier). + this.getNumberOfParameters() = 0 and not this.isStatic() } } From 1c50c0c2c6b70e5f16d1117b22f5587610370556 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 5 May 2026 11:23:37 +0200 Subject: [PATCH 20/36] C#: Update PrintAst expected output. --- .../library-tests/operators/PrintAst.expected | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/csharp/ql/test/library-tests/operators/PrintAst.expected b/csharp/ql/test/library-tests/operators/PrintAst.expected index 1c335faddb0..2087e5f96dc 100644 --- a/csharp/ql/test/library-tests/operators/PrintAst.expected +++ b/csharp/ql/test/library-tests/operators/PrintAst.expected @@ -182,16 +182,16 @@ operators.cs: # 48| -1: [TypeMention] IntVector # 48| 4: [BlockStmt] {...} # 51| 2: [Class] C -# 54| 6: [???] checked ++= +# 54| 6: [CheckedIncrementOperator] checked ++ # 54| -1: [TypeMention] Void # 54| 4: [BlockStmt] {...} -# 55| 7: [???] ++= +# 55| 7: [IncrementOperator] ++ # 55| -1: [TypeMention] Void # 55| 4: [BlockStmt] {...} -# 56| 8: [???] checked --= +# 56| 8: [CheckedDecrementOperator] checked -- # 56| -1: [TypeMention] Void # 56| 4: [BlockStmt] {...} -# 57| 9: [???] --= +# 57| 9: [DecrementOperator] -- # 57| -1: [TypeMention] Void # 57| 4: [BlockStmt] {...} # 60| 3: [Class] TestOperator @@ -294,30 +294,30 @@ operators.cs: # 92| 1: [ObjectCreation] object creation of type C # 92| 0: [TypeMention] C # 93| 18: [ExprStmt] ...; -# 93| 0: [OperatorCall] call to operator ++= +# 93| 0: [OperatorCall] call to operator ++ # 93| 0: [LocalVariableAccess] access to local variable c # 94| 19: [ExprStmt] ...; -# 94| 0: [OperatorCall] call to operator ++= +# 94| 0: [OperatorCall] call to operator ++ # 94| 0: [LocalVariableAccess] access to local variable c # 95| 20: [ExprStmt] ...; -# 95| 0: [OperatorCall] call to operator --= +# 95| 0: [OperatorCall] call to operator -- # 95| 0: [LocalVariableAccess] access to local variable c # 96| 21: [ExprStmt] ...; -# 96| 0: [OperatorCall] call to operator --= +# 96| 0: [OperatorCall] call to operator -- # 96| 0: [LocalVariableAccess] access to local variable c # 98| 22: [CheckedStmt] checked {...} # 99| 0: [BlockStmt] {...} # 100| 0: [ExprStmt] ...; -# 100| 0: [OperatorCall] call to operator checked ++= +# 100| 0: [OperatorCall] call to operator checked ++ # 100| 0: [LocalVariableAccess] access to local variable c # 101| 1: [ExprStmt] ...; -# 101| 0: [OperatorCall] call to operator checked ++= +# 101| 0: [OperatorCall] call to operator checked ++ # 101| 0: [LocalVariableAccess] access to local variable c # 102| 2: [ExprStmt] ...; -# 102| 0: [OperatorCall] call to operator checked --= +# 102| 0: [OperatorCall] call to operator checked -- # 102| 0: [LocalVariableAccess] access to local variable c # 103| 3: [ExprStmt] ...; -# 103| 0: [OperatorCall] call to operator checked --= +# 103| 0: [OperatorCall] call to operator checked -- # 103| 0: [LocalVariableAccess] access to local variable c # 107| 7: [Struct] Digit # 109| 6: [Field] value From 25274a1df29b1de0de1849785a2e30e5c2648742 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 5 May 2026 09:53:13 +0200 Subject: [PATCH 21/36] C#: Add an increment/decrement operator test case. --- .../library-tests/operators/Operators6.expected | 10 ++++++++++ .../test/library-tests/operators/Operators6.ql | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 csharp/ql/test/library-tests/operators/Operators6.expected create mode 100644 csharp/ql/test/library-tests/operators/Operators6.ql diff --git a/csharp/ql/test/library-tests/operators/Operators6.expected b/csharp/ql/test/library-tests/operators/Operators6.expected new file mode 100644 index 00000000000..f0878a511d9 --- /dev/null +++ b/csharp/ql/test/library-tests/operators/Operators6.expected @@ -0,0 +1,10 @@ +| operators.cs:15:42:15:43 | ++ | operators.cs:66:19:66:23 | call to operator ++ | +| operators.cs:15:42:15:43 | ++ | operators.cs:67:19:67:23 | call to operator ++ | +| operators.cs:54:38:54:39 | checked ++ | operators.cs:100:17:100:19 | call to operator checked ++ | +| operators.cs:54:38:54:39 | checked ++ | operators.cs:101:17:101:19 | call to operator checked ++ | +| operators.cs:55:30:55:31 | ++ | operators.cs:93:13:93:15 | call to operator ++ | +| operators.cs:55:30:55:31 | ++ | operators.cs:94:13:94:15 | call to operator ++ | +| operators.cs:56:38:56:39 | checked -- | operators.cs:102:17:102:19 | call to operator checked -- | +| operators.cs:56:38:56:39 | checked -- | operators.cs:103:17:103:19 | call to operator checked -- | +| operators.cs:57:30:57:31 | -- | operators.cs:95:13:95:15 | call to operator -- | +| operators.cs:57:30:57:31 | -- | operators.cs:96:13:96:15 | call to operator -- | diff --git a/csharp/ql/test/library-tests/operators/Operators6.ql b/csharp/ql/test/library-tests/operators/Operators6.ql new file mode 100644 index 00000000000..0eb578a1134 --- /dev/null +++ b/csharp/ql/test/library-tests/operators/Operators6.ql @@ -0,0 +1,17 @@ +/** + * @name Test for operators + */ + +import csharp + +from Operator op, OperatorCall call +where + op.fromSource() and + ( + op instanceof IncrementOperator or + op instanceof CheckedIncrementOperator or + op instanceof DecrementOperator or + op instanceof CheckedDecrementOperator + ) and + call.getTarget() = op +select op, call From 9a805080ea828de2d42fa76b0589528668007f4b Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 6 May 2026 09:43:35 +0200 Subject: [PATCH 22/36] C#: Improve the GetCallType method to also take extension operators into account. --- .../Semmle.Extraction.CSharp/Entities/Expression.cs | 12 ++++++------ .../Entities/Expressions/Invocation.cs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs index 4ab90def2c1..bf02ba49a2b 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs @@ -234,9 +234,9 @@ namespace Semmle.Extraction.CSharp.Entities /// /// The expression syntax node. /// Returns the target method symbol, or null if it cannot be resolved. - protected IMethodSymbol? GetTargetSymbol(ExpressionSyntax node) + protected static IMethodSymbol? GetTargetSymbol(Context cx, ExpressionSyntax node) { - var si = Context.GetSymbolInfo(node); + var si = cx.GetSymbolInfo(node); if (si.Symbol is ISymbol symbol) { var method = symbol as IMethodSymbol; @@ -255,7 +255,7 @@ namespace Semmle.Extraction.CSharp.Entities .Where(method => method.Parameters.Length >= syntax.ArgumentList.Arguments.Count) .Where(method => method.Parameters.Count(p => !p.HasExplicitDefaultValue) <= syntax.ArgumentList.Arguments.Count); - return Context.ExtractionContext.IsStandalone ? + return cx.ExtractionContext.IsStandalone ? candidates.FirstOrDefault() : candidates.SingleOrDefault(); } @@ -281,7 +281,7 @@ namespace Semmle.Extraction.CSharp.Entities /// The expression. public void AddOperatorCall(TextWriter trapFile, ExpressionSyntax node) { - var @operator = GetTargetSymbol(node); + var @operator = GetTargetSymbol(Context, node); if (@operator is IMethodSymbol method) { var callType = GetCallType(Context, node); @@ -312,9 +312,9 @@ namespace Semmle.Extraction.CSharp.Entities /// The call type. public static CallType GetCallType(Context cx, ExpressionSyntax node) { - var @operator = cx.GetSymbolInfo(node); + var @operator = GetTargetSymbol(cx, node); - if (@operator.Symbol is IMethodSymbol method) + if (@operator is IMethodSymbol method) { if (method.ContainingSymbol is ITypeSymbol containingSymbol && containingSymbol.TypeKind == Microsoft.CodeAnalysis.TypeKind.Dynamic) { diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs index 343f288eeaf..5b25e53e8ee 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Invocation.cs @@ -44,7 +44,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var child = -1; string? memberName = null; - var target = GetTargetSymbol(Syntax); + var target = GetTargetSymbol(Context, Syntax); switch (Syntax.Expression) { case MemberAccessExpressionSyntax memberAccess when IsValidMemberAccessKind(): From 23328e90d422f187d51a48da30a5f568508787be Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 11 May 2026 12:57:00 +0200 Subject: [PATCH 23/36] C#: Add extension increment/decrement examples. --- .../library-tests/extension/PrintAst.expected | 564 +++++++++--------- .../extension/extensionTypes.expected | 20 +- .../library-tests/extension/extensions.cs | 8 +- .../extension/extensions.expected | 188 +++--- 4 files changed, 412 insertions(+), 368 deletions(-) diff --git a/csharp/ql/test/library-tests/extension/PrintAst.expected b/csharp/ql/test/library-tests/extension/PrintAst.expected index 5016665c08b..f05e3969261 100644 --- a/csharp/ql/test/library-tests/extension/PrintAst.expected +++ b/csharp/ql/test/library-tests/extension/PrintAst.expected @@ -171,311 +171,341 @@ extensions.cs: # 16| 4: [BlockStmt] {...} # 16| 0: [ReturnStmt] return ...; # 16| 0: [ParameterAccess] access to parameter t -# 19| 5: [ExtensionType] extension(Object) -# 21| 4: [ExtensionMethod] StaticObjectM1 -# 21| -1: [TypeMention] int -# 21| 4: [BlockStmt] {...} -# 21| 0: [ReturnStmt] return ...; -# 21| 0: [IntLiteral] 0 -# 22| 5: [ExtensionMethod] StaticObjectM2 -# 22| -1: [TypeMention] int +# 17| 15: [ExtensionCallable,IncrementOperator] ++ +# 17| -1: [TypeMention] Void #-----| 2: (Parameters) -# 22| 0: [Parameter] s -# 22| -1: [TypeMention] string -# 22| 4: [BlockStmt] {...} -# 22| 0: [ReturnStmt] return ...; -# 22| 0: [PropertyCall] access to property Length -# 22| -1: [ParameterAccess] access to parameter s -# 23| 6: [Property] StaticProp -# 23| -1: [TypeMention] bool -# 23| 3: [ExtensionCallable,Getter] get_StaticProp -# 23| 4: [BoolLiteral] true -# 26| 8: [ExtensionType] extension(T)`1 +# 6| 0: [Parameter] s +# 6| -1: [TypeMention] string +# 17| 4: [BlockStmt] {...} +# 18| 16: [DecrementOperator,ExtensionCallable] -- +# 18| -1: [TypeMention] string +#-----| 2: (Parameters) +# 18| 0: [Parameter] o +# 18| -1: [TypeMention] string +# 18| 4: [BlockStmt] {...} +# 18| 0: [ReturnStmt] return ...; +# 18| 0: [ParameterAccess] access to parameter o +# 21| 5: [ExtensionType] extension(Object) +# 23| 4: [ExtensionMethod] StaticObjectM1 +# 23| -1: [TypeMention] int +# 23| 4: [BlockStmt] {...} +# 23| 0: [ReturnStmt] return ...; +# 23| 0: [IntLiteral] 0 +# 24| 5: [ExtensionMethod] StaticObjectM2 +# 24| -1: [TypeMention] int +#-----| 2: (Parameters) +# 24| 0: [Parameter] s +# 24| -1: [TypeMention] string +# 24| 4: [BlockStmt] {...} +# 24| 0: [ReturnStmt] return ...; +# 24| 0: [PropertyCall] access to property Length +# 24| -1: [ParameterAccess] access to parameter s +# 25| 6: [Property] StaticProp +# 25| -1: [TypeMention] bool +# 25| 3: [ExtensionCallable,Getter] get_StaticProp +# 25| 4: [BoolLiteral] true +# 28| 8: [ExtensionType] extension(T)`1 #-----| 1: (Type parameters) -# 26| 0: [TypeParameter] T +# 28| 0: [TypeParameter] T #-----| 2: (Parameters) -# 26| 0: [Parameter] t -# 26| -1: [TypeMention] T -# 28| 4: [Property] GenericProp1 -# 28| -1: [TypeMention] bool -# 28| 3: [ExtensionCallable,Getter] get_GenericProp1 -#-----| 2: (Parameters) -# 26| 0: [Parameter] t -# 26| -1: [TypeMention] T -# 28| 4: [IsExpr] ... is ... -# 28| 0: [SyntheticExtensionParameterAccess] access to extension synthetic parameter t -# 28| 1: [NotPatternExpr] not ... -# 28| 0: [ConstantPatternExpr,NullLiteral] null -# 29| 5: [Property] GenericProp2 -# 29| -1: [TypeMention] bool -# 29| 3: [ExtensionCallable,Getter] get_GenericProp2 -#-----| 2: (Parameters) -# 26| 0: [Parameter] t -# 26| -1: [TypeMention] T -# 29| 4: [BlockStmt] {...} -# 29| 0: [ReturnStmt] return ...; -# 29| 0: [BoolLiteral] true -# 29| 4: [ExtensionCallable,Setter] set_GenericProp2 -#-----| 2: (Parameters) -# 26| 0: [Parameter] t -# 26| -1: [TypeMention] T -# 29| 1: [Parameter] value -# 29| 4: [BlockStmt] {...} -# 30| 6: [ExtensionMethod] GenericM1 +# 28| 0: [Parameter] t +# 28| -1: [TypeMention] T +# 30| 4: [Property] GenericProp1 # 30| -1: [TypeMention] bool +# 30| 3: [ExtensionCallable,Getter] get_GenericProp1 +#-----| 2: (Parameters) +# 28| 0: [Parameter] t +# 28| -1: [TypeMention] T +# 30| 4: [IsExpr] ... is ... +# 30| 0: [SyntheticExtensionParameterAccess] access to extension synthetic parameter t +# 30| 1: [NotPatternExpr] not ... +# 30| 0: [ConstantPatternExpr,NullLiteral] null +# 31| 5: [Property] GenericProp2 +# 31| -1: [TypeMention] bool +# 31| 3: [ExtensionCallable,Getter] get_GenericProp2 +#-----| 2: (Parameters) +# 28| 0: [Parameter] t +# 28| -1: [TypeMention] T +# 31| 4: [BlockStmt] {...} +# 31| 0: [ReturnStmt] return ...; +# 31| 0: [BoolLiteral] true +# 31| 4: [ExtensionCallable,Setter] set_GenericProp2 +#-----| 2: (Parameters) +# 28| 0: [Parameter] t +# 28| -1: [TypeMention] T +# 31| 1: [Parameter] value +# 31| 4: [BlockStmt] {...} +# 32| 6: [ExtensionMethod] GenericM1 +# 32| -1: [TypeMention] bool #-----| 2: (Parameters) -# 26| 0: [Parameter] t -# 26| -1: [TypeMention] T -# 30| 4: [IsExpr] ... is ... -# 30| 0: [SyntheticExtensionParameterAccess] access to extension synthetic parameter t -# 30| 1: [NotPatternExpr] not ... -# 30| 0: [ConstantPatternExpr,NullLiteral] null -# 31| 7: [ExtensionMethod] GenericM2`1 -# 31| -1: [TypeMention] Void -#-----| 1: (Type parameters) -# 31| 0: [TypeParameter] S -#-----| 2: (Parameters) -# 26| 0: [Parameter] t -# 26| -1: [TypeMention] T -# 31| 1: [Parameter] other -# 31| -1: [TypeMention] S -# 31| 4: [BlockStmt] {...} -# 32| 8: [ExtensionMethod] GenericStaticM1 -# 32| -1: [TypeMention] Void -#-----| 2: (Parameters) -# 26| 0: [Parameter] t -# 26| -1: [TypeMention] T -# 32| 4: [BlockStmt] {...} -# 33| 9: [ExtensionMethod] GenericStaticM2`1 +# 28| 0: [Parameter] t +# 28| -1: [TypeMention] T +# 32| 4: [IsExpr] ... is ... +# 32| 0: [SyntheticExtensionParameterAccess] access to extension synthetic parameter t +# 32| 1: [NotPatternExpr] not ... +# 32| 0: [ConstantPatternExpr,NullLiteral] null +# 33| 7: [ExtensionMethod] GenericM2`1 # 33| -1: [TypeMention] Void #-----| 1: (Type parameters) # 33| 0: [TypeParameter] S #-----| 2: (Parameters) -# 33| 0: [Parameter] other +# 28| 0: [Parameter] t +# 28| -1: [TypeMention] T +# 33| 1: [Parameter] other # 33| -1: [TypeMention] S # 33| 4: [BlockStmt] {...} -# 34| 10: [AddOperator,ExtensionCallable] + -# 34| -1: [TypeMention] T +# 34| 8: [ExtensionMethod] GenericStaticM1 +# 34| -1: [TypeMention] Void #-----| 2: (Parameters) -# 34| 0: [Parameter] a -# 34| -1: [TypeMention] T -# 34| 1: [Parameter] b -# 34| -1: [TypeMention] T +# 28| 0: [Parameter] t +# 28| -1: [TypeMention] T # 34| 4: [BlockStmt] {...} -# 34| 0: [ReturnStmt] return ...; -# 34| 0: [NullLiteral] null -# 38| [Class] ClassicExtensions -# 40| 4: [ExtensionMethod] M3 -# 40| -1: [TypeMention] bool +# 35| 9: [ExtensionMethod] GenericStaticM2`1 +# 35| -1: [TypeMention] Void +#-----| 1: (Type parameters) +# 35| 0: [TypeParameter] S +#-----| 2: (Parameters) +# 35| 0: [Parameter] other +# 35| -1: [TypeMention] S +# 35| 4: [BlockStmt] {...} +# 36| 10: [AddOperator,ExtensionCallable] + +# 36| -1: [TypeMention] T +#-----| 2: (Parameters) +# 36| 0: [Parameter] a +# 36| -1: [TypeMention] T +# 36| 1: [Parameter] b +# 36| -1: [TypeMention] T +# 36| 4: [BlockStmt] {...} +# 36| 0: [ReturnStmt] return ...; +# 36| 0: [NullLiteral] null +# 40| [Class] ClassicExtensions +# 42| 4: [ExtensionMethod] M3 +# 42| -1: [TypeMention] bool #-----| 2: (Parameters) -# 40| 0: [Parameter] s -# 40| -1: [TypeMention] string -# 40| 4: [IsExpr] ... is ... -# 40| 0: [ParameterAccess] access to parameter s -# 40| 1: [NotPatternExpr] not ... -# 40| 0: [ConstantPatternExpr,NullLiteral] null -# 43| [Class] C -# 45| 6: [Method] CallingExtensions -# 45| -1: [TypeMention] Void -# 46| 4: [BlockStmt] {...} -# 47| 0: [LocalVariableDeclStmt] ... ...; -# 47| 0: [LocalVariableDeclAndInitExpr] String s = ... -# 47| -1: [TypeMention] string -# 47| 0: [LocalVariableAccess] access to local variable s -# 47| 1: [StringLiteralUtf16] "Hello World." -# 50| 1: [LocalVariableDeclStmt] ... ...; -# 50| 0: [LocalVariableDeclAndInitExpr] Boolean x11 = ... -# 50| -1: [TypeMention] bool -# 50| 0: [LocalVariableAccess] access to local variable x11 -# 50| 1: [ExtensionPropertyCall] access to property Prop1 -# 50| -1: [LocalVariableAccess] access to local variable s -# 51| 2: [LocalVariableDeclStmt] ... ...; -# 51| 0: [LocalVariableDeclAndInitExpr] Boolean x12 = ... -# 51| -1: [TypeMention] bool -# 51| 0: [LocalVariableAccess] access to local variable x12 -# 51| 1: [ExtensionPropertyCall] access to property Prop2 -# 51| -1: [LocalVariableAccess] access to local variable s -# 52| 3: [ExprStmt] ...; -# 52| 0: [AssignExpr] ... = ... -# 52| 0: [ExtensionPropertyCall] access to property Prop2 +# 42| 0: [Parameter] s +# 42| -1: [TypeMention] string +# 42| 4: [IsExpr] ... is ... +# 42| 0: [ParameterAccess] access to parameter s +# 42| 1: [NotPatternExpr] not ... +# 42| 0: [ConstantPatternExpr,NullLiteral] null +# 45| [Class] C +# 47| 6: [Method] CallingExtensions +# 47| -1: [TypeMention] Void +# 48| 4: [BlockStmt] {...} +# 49| 0: [LocalVariableDeclStmt] ... ...; +# 49| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 49| -1: [TypeMention] string +# 49| 0: [LocalVariableAccess] access to local variable s +# 49| 1: [StringLiteralUtf16] "Hello World." +# 52| 1: [LocalVariableDeclStmt] ... ...; +# 52| 0: [LocalVariableDeclAndInitExpr] Boolean x11 = ... +# 52| -1: [TypeMention] bool +# 52| 0: [LocalVariableAccess] access to local variable x11 +# 52| 1: [ExtensionPropertyCall] access to property Prop1 # 52| -1: [LocalVariableAccess] access to local variable s -# 52| 1: [BoolLiteral] true -# 53| 4: [LocalVariableDeclStmt] ... ...; -# 53| 0: [LocalVariableDeclAndInitExpr] Boolean x13 = ... +# 53| 2: [LocalVariableDeclStmt] ... ...; +# 53| 0: [LocalVariableDeclAndInitExpr] Boolean x12 = ... # 53| -1: [TypeMention] bool -# 53| 0: [LocalVariableAccess] access to local variable x13 -# 53| 1: [ExtensionPropertyCall] access to property StaticProp1 -# 53| -1: [TypeAccess] access to type String -# 53| 0: [TypeMention] string -# 54| 5: [LocalVariableDeclStmt] ... ...; -# 54| 0: [LocalVariableDeclAndInitExpr] Boolean x14 = ... -# 54| -1: [TypeMention] bool -# 54| 0: [LocalVariableAccess] access to local variable x14 -# 54| 1: [ExtensionPropertyCall] access to property StaticProp -# 54| -1: [TypeAccess] access to type Object -# 54| 0: [TypeMention] object -# 57| 6: [LocalVariableDeclStmt] ... ...; -# 57| 0: [LocalVariableDeclAndInitExpr] Boolean x21 = ... -# 57| -1: [TypeMention] bool -# 57| 0: [LocalVariableAccess] access to local variable x21 -# 57| 1: [MethodCall] call to method M1 -# 57| -1: [LocalVariableAccess] access to local variable s -# 58| 7: [LocalVariableDeclStmt] ... ...; -# 58| 0: [LocalVariableDeclAndInitExpr] String x22 = ... -# 58| -1: [TypeMention] string -# 58| 0: [LocalVariableAccess] access to local variable x22 -# 58| 1: [MethodCall] call to method M2 -# 58| -1: [LocalVariableAccess] access to local variable s -# 58| 0: [StringLiteralUtf16] "!!!" -# 59| 8: [LocalVariableDeclStmt] ... ...; -# 59| 0: [LocalVariableDeclAndInitExpr] Int32 x23 = ... -# 59| -1: [TypeMention] int -# 59| 0: [LocalVariableAccess] access to local variable x23 -# 59| 1: [MethodCall] call to method StaticM1 -# 59| -1: [TypeAccess] access to type String -# 59| 0: [TypeMention] string -# 60| 9: [LocalVariableDeclStmt] ... ...; -# 60| 0: [LocalVariableDeclAndInitExpr] Int32 x24 = ... -# 60| -1: [TypeMention] int -# 60| 0: [LocalVariableAccess] access to local variable x24 -# 60| 1: [MethodCall] call to method StaticM2 -# 60| -1: [TypeAccess] access to type String -# 60| 0: [TypeMention] string -# 60| 0: [LocalVariableAccess] access to local variable s -# 61| 10: [LocalVariableDeclStmt] ... ...; -# 61| 0: [LocalVariableDeclAndInitExpr] Int32 x25 = ... +# 53| 0: [LocalVariableAccess] access to local variable x12 +# 53| 1: [ExtensionPropertyCall] access to property Prop2 +# 53| -1: [LocalVariableAccess] access to local variable s +# 54| 3: [ExprStmt] ...; +# 54| 0: [AssignExpr] ... = ... +# 54| 0: [ExtensionPropertyCall] access to property Prop2 +# 54| -1: [LocalVariableAccess] access to local variable s +# 54| 1: [BoolLiteral] true +# 55| 4: [LocalVariableDeclStmt] ... ...; +# 55| 0: [LocalVariableDeclAndInitExpr] Boolean x13 = ... +# 55| -1: [TypeMention] bool +# 55| 0: [LocalVariableAccess] access to local variable x13 +# 55| 1: [ExtensionPropertyCall] access to property StaticProp1 +# 55| -1: [TypeAccess] access to type String +# 55| 0: [TypeMention] string +# 56| 5: [LocalVariableDeclStmt] ... ...; +# 56| 0: [LocalVariableDeclAndInitExpr] Boolean x14 = ... +# 56| -1: [TypeMention] bool +# 56| 0: [LocalVariableAccess] access to local variable x14 +# 56| 1: [ExtensionPropertyCall] access to property StaticProp +# 56| -1: [TypeAccess] access to type Object +# 56| 0: [TypeMention] object +# 59| 6: [LocalVariableDeclStmt] ... ...; +# 59| 0: [LocalVariableDeclAndInitExpr] Boolean x21 = ... +# 59| -1: [TypeMention] bool +# 59| 0: [LocalVariableAccess] access to local variable x21 +# 59| 1: [MethodCall] call to method M1 +# 59| -1: [LocalVariableAccess] access to local variable s +# 60| 7: [LocalVariableDeclStmt] ... ...; +# 60| 0: [LocalVariableDeclAndInitExpr] String x22 = ... +# 60| -1: [TypeMention] string +# 60| 0: [LocalVariableAccess] access to local variable x22 +# 60| 1: [MethodCall] call to method M2 +# 60| -1: [LocalVariableAccess] access to local variable s +# 60| 0: [StringLiteralUtf16] "!!!" +# 61| 8: [LocalVariableDeclStmt] ... ...; +# 61| 0: [LocalVariableDeclAndInitExpr] Int32 x23 = ... # 61| -1: [TypeMention] int -# 61| 0: [LocalVariableAccess] access to local variable x25 -# 61| 1: [MethodCall] call to method StaticObjectM1 -# 61| -1: [TypeAccess] access to type Object -# 61| 0: [TypeMention] object -# 62| 11: [LocalVariableDeclStmt] ... ...; -# 62| 0: [LocalVariableDeclAndInitExpr] Int32 x26 = ... +# 61| 0: [LocalVariableAccess] access to local variable x23 +# 61| 1: [MethodCall] call to method StaticM1 +# 61| -1: [TypeAccess] access to type String +# 61| 0: [TypeMention] string +# 62| 9: [LocalVariableDeclStmt] ... ...; +# 62| 0: [LocalVariableDeclAndInitExpr] Int32 x24 = ... # 62| -1: [TypeMention] int -# 62| 0: [LocalVariableAccess] access to local variable x26 -# 62| 1: [MethodCall] call to method StaticObjectM2 -# 62| -1: [TypeAccess] access to type Object -# 62| 0: [TypeMention] object +# 62| 0: [LocalVariableAccess] access to local variable x24 +# 62| 1: [MethodCall] call to method StaticM2 +# 62| -1: [TypeAccess] access to type String +# 62| 0: [TypeMention] string # 62| 0: [LocalVariableAccess] access to local variable s -# 65| 12: [LocalVariableDeclStmt] ... ...; -# 65| 0: [LocalVariableDeclAndInitExpr] String x30 = ... -# 65| -1: [TypeMention] string -# 65| 0: [LocalVariableAccess] access to local variable x30 -# 65| 1: [ExtensionOperatorCall] call to operator * -# 65| 0: [IntLiteral] 3 -# 65| 1: [LocalVariableAccess] access to local variable s -# 68| 13: [LocalVariableDeclStmt] ... ...; -# 68| 0: [LocalVariableDeclAndInitExpr] Boolean y = ... -# 68| -1: [TypeMention] bool -# 68| 0: [LocalVariableAccess] access to local variable y -# 68| 1: [MethodCall] call to method M3 -# 68| -1: [LocalVariableAccess] access to local variable s -# 71| 14: [ExprStmt] ...; -# 71| 0: [MethodCall] call to method M1 -# 71| -1: [TypeAccess] access to type MyExtensions -# 71| 0: [TypeMention] MyExtensions -# 71| 0: [LocalVariableAccess] access to local variable s -# 72| 15: [ExprStmt] ...; -# 72| 0: [MethodCall] call to method M2 -# 72| -1: [TypeAccess] access to type MyExtensions -# 72| 0: [TypeMention] MyExtensions -# 72| 0: [LocalVariableAccess] access to local variable s -# 72| 1: [StringLiteralUtf16] "!!!" -# 73| 16: [ExprStmt] ...; -# 73| 0: [MethodCall] call to method StaticM1 -# 73| -1: [TypeAccess] access to type MyExtensions -# 73| 0: [TypeMention] MyExtensions -# 74| 17: [ExprStmt] ...; -# 74| 0: [MethodCall] call to method StaticM2 -# 74| -1: [TypeAccess] access to type MyExtensions -# 74| 0: [TypeMention] MyExtensions -# 74| 0: [LocalVariableAccess] access to local variable s -# 75| 18: [ExprStmt] ...; -# 75| 0: [MethodCall] call to method StaticObjectM1 +# 63| 10: [LocalVariableDeclStmt] ... ...; +# 63| 0: [LocalVariableDeclAndInitExpr] Int32 x25 = ... +# 63| -1: [TypeMention] int +# 63| 0: [LocalVariableAccess] access to local variable x25 +# 63| 1: [MethodCall] call to method StaticObjectM1 +# 63| -1: [TypeAccess] access to type Object +# 63| 0: [TypeMention] object +# 64| 11: [LocalVariableDeclStmt] ... ...; +# 64| 0: [LocalVariableDeclAndInitExpr] Int32 x26 = ... +# 64| -1: [TypeMention] int +# 64| 0: [LocalVariableAccess] access to local variable x26 +# 64| 1: [MethodCall] call to method StaticObjectM2 +# 64| -1: [TypeAccess] access to type Object +# 64| 0: [TypeMention] object +# 64| 0: [LocalVariableAccess] access to local variable s +# 67| 12: [LocalVariableDeclStmt] ... ...; +# 67| 0: [LocalVariableDeclAndInitExpr] String x30 = ... +# 67| -1: [TypeMention] string +# 67| 0: [LocalVariableAccess] access to local variable x30 +# 67| 1: [ExtensionOperatorCall] call to operator * +# 67| 0: [IntLiteral] 3 +# 67| 1: [LocalVariableAccess] access to local variable s +# 68| 13: [ExprStmt] ...; +# 68| 0: [ExtensionOperatorCall] call to operator ++ +# 68| 0: [LocalVariableAccess] access to local variable s +# 69| 14: [ExprStmt] ...; +# 69| 0: [ExtensionOperatorCall] call to operator -- +# 69| 0: [LocalVariableAccess] access to local variable s +# 72| 15: [LocalVariableDeclStmt] ... ...; +# 72| 0: [LocalVariableDeclAndInitExpr] Boolean y = ... +# 72| -1: [TypeMention] bool +# 72| 0: [LocalVariableAccess] access to local variable y +# 72| 1: [MethodCall] call to method M3 +# 72| -1: [LocalVariableAccess] access to local variable s +# 75| 16: [ExprStmt] ...; +# 75| 0: [MethodCall] call to method M1 # 75| -1: [TypeAccess] access to type MyExtensions # 75| 0: [TypeMention] MyExtensions -# 76| 19: [ExprStmt] ...; -# 76| 0: [MethodCall] call to method StaticObjectM2 +# 75| 0: [LocalVariableAccess] access to local variable s +# 76| 17: [ExprStmt] ...; +# 76| 0: [MethodCall] call to method M2 # 76| -1: [TypeAccess] access to type MyExtensions # 76| 0: [TypeMention] MyExtensions # 76| 0: [LocalVariableAccess] access to local variable s +# 76| 1: [StringLiteralUtf16] "!!!" +# 77| 18: [ExprStmt] ...; +# 77| 0: [MethodCall] call to method StaticM1 +# 77| -1: [TypeAccess] access to type MyExtensions +# 77| 0: [TypeMention] MyExtensions +# 78| 19: [ExprStmt] ...; +# 78| 0: [MethodCall] call to method StaticM2 +# 78| -1: [TypeAccess] access to type MyExtensions +# 78| 0: [TypeMention] MyExtensions +# 78| 0: [LocalVariableAccess] access to local variable s # 79| 20: [ExprStmt] ...; -# 79| 0: [ExtensionOperatorCall] call to operator * +# 79| 0: [MethodCall] call to method StaticObjectM1 # 79| -1: [TypeAccess] access to type MyExtensions # 79| 0: [TypeMention] MyExtensions -# 79| 0: [IntLiteral] 3 -# 79| 1: [LocalVariableAccess] access to local variable s -# 82| 21: [ExprStmt] ...; -# 82| 0: [MethodCall] call to extension accessor get_Prop1 -# 82| -1: [TypeAccess] access to type MyExtensions -# 82| 0: [TypeMention] MyExtensions -# 82| 0: [LocalVariableAccess] access to local variable s +# 80| 21: [ExprStmt] ...; +# 80| 0: [MethodCall] call to method StaticObjectM2 +# 80| -1: [TypeAccess] access to type MyExtensions +# 80| 0: [TypeMention] MyExtensions +# 80| 0: [LocalVariableAccess] access to local variable s # 83| 22: [ExprStmt] ...; -# 83| 0: [MethodCall] call to extension accessor get_Prop2 +# 83| 0: [ExtensionOperatorCall] call to operator * # 83| -1: [TypeAccess] access to type MyExtensions # 83| 0: [TypeMention] MyExtensions -# 83| 0: [LocalVariableAccess] access to local variable s +# 83| 0: [IntLiteral] 3 +# 83| 1: [LocalVariableAccess] access to local variable s # 84| 23: [ExprStmt] ...; -# 84| 0: [MethodCall] call to extension accessor set_Prop2 +# 84| 0: [ExtensionOperatorCall] call to operator ++ # 84| -1: [TypeAccess] access to type MyExtensions # 84| 0: [TypeMention] MyExtensions # 84| 0: [LocalVariableAccess] access to local variable s -# 84| 1: [BoolLiteral] false # 85| 24: [ExprStmt] ...; -# 85| 0: [MethodCall] call to extension accessor get_StaticProp +# 85| 0: [ExtensionOperatorCall] call to operator -- # 85| -1: [TypeAccess] access to type MyExtensions # 85| 0: [TypeMention] MyExtensions -# 88| 7: [Method] CallingGenericExtensions -# 88| -1: [TypeMention] Void -# 89| 4: [BlockStmt] {...} -# 90| 0: [LocalVariableDeclStmt] ... ...; -# 90| 0: [LocalVariableDeclAndInitExpr] String s = ... -# 90| -1: [TypeMention] string +# 85| 0: [LocalVariableAccess] access to local variable s +# 88| 25: [ExprStmt] ...; +# 88| 0: [MethodCall] call to extension accessor get_Prop1 +# 88| -1: [TypeAccess] access to type MyExtensions +# 88| 0: [TypeMention] MyExtensions +# 88| 0: [LocalVariableAccess] access to local variable s +# 89| 26: [ExprStmt] ...; +# 89| 0: [MethodCall] call to extension accessor get_Prop2 +# 89| -1: [TypeAccess] access to type MyExtensions +# 89| 0: [TypeMention] MyExtensions +# 89| 0: [LocalVariableAccess] access to local variable s +# 90| 27: [ExprStmt] ...; +# 90| 0: [MethodCall] call to extension accessor set_Prop2 +# 90| -1: [TypeAccess] access to type MyExtensions +# 90| 0: [TypeMention] MyExtensions # 90| 0: [LocalVariableAccess] access to local variable s -# 90| 1: [StringLiteralUtf16] "Hello Generic World." -# 91| 1: [LocalVariableDeclStmt] ... ...; -# 91| 0: [LocalVariableDeclAndInitExpr] Object o = ... -# 91| -1: [TypeMention] object -# 91| 0: [LocalVariableAccess] access to local variable o -# 91| 1: [ObjectCreation] object creation of type Object -# 91| 0: [TypeMention] object -# 94| 2: [ExprStmt] ...; -# 94| 0: [MethodCall] call to method GenericM1 -# 94| -1: [LocalVariableAccess] access to local variable o -# 95| 3: [ExprStmt] ...; -# 95| 0: [MethodCall] call to method GenericM1 -# 95| -1: [LocalVariableAccess] access to local variable s -# 98| 4: [ExprStmt] ...; -# 98| 0: [MethodCall] call to method GenericM1 -# 98| -1: [TypeAccess] access to type MyExtensions -# 98| 0: [TypeMention] MyExtensions -# 98| 0: [LocalVariableAccess] access to local variable o -# 99| 5: [ExprStmt] ...; -# 99| 0: [MethodCall] call to method GenericM1 -# 99| -1: [TypeAccess] access to type MyExtensions -# 99| 0: [TypeMention] MyExtensions -# 99| 0: [LocalVariableAccess] access to local variable s -# 101| 6: [ExprStmt] ...; -# 101| 0: [MethodCall] call to method GenericM2 -# 101| -1: [LocalVariableAccess] access to local variable o -# 101| 0: [IntLiteral] 42 -# 102| 7: [ExprStmt] ...; -# 102| 0: [MethodCall] call to method GenericM2 -# 102| -1: [TypeAccess] access to type MyExtensions -# 102| 0: [TypeMention] MyExtensions -# 102| 0: [LocalVariableAccess] access to local variable o -# 102| 1: [IntLiteral] 42 -# 104| 8: [ExprStmt] ...; -# 104| 0: [MethodCall] call to method StringGenericM1 -# 104| -1: [LocalVariableAccess] access to local variable s -# 104| 0: [IntLiteral] 7 -# 104| 1: [ObjectCreation] object creation of type Object -# 104| 0: [TypeMention] object -# 105| 9: [ExprStmt] ...; -# 105| 0: [MethodCall] call to method StringGenericM1 +# 90| 1: [BoolLiteral] false +# 91| 28: [ExprStmt] ...; +# 91| 0: [MethodCall] call to extension accessor get_StaticProp +# 91| -1: [TypeAccess] access to type MyExtensions +# 91| 0: [TypeMention] MyExtensions +# 94| 7: [Method] CallingGenericExtensions +# 94| -1: [TypeMention] Void +# 95| 4: [BlockStmt] {...} +# 96| 0: [LocalVariableDeclStmt] ... ...; +# 96| 0: [LocalVariableDeclAndInitExpr] String s = ... +# 96| -1: [TypeMention] string +# 96| 0: [LocalVariableAccess] access to local variable s +# 96| 1: [StringLiteralUtf16] "Hello Generic World." +# 97| 1: [LocalVariableDeclStmt] ... ...; +# 97| 0: [LocalVariableDeclAndInitExpr] Object o = ... +# 97| -1: [TypeMention] object +# 97| 0: [LocalVariableAccess] access to local variable o +# 97| 1: [ObjectCreation] object creation of type Object +# 97| 0: [TypeMention] object +# 100| 2: [ExprStmt] ...; +# 100| 0: [MethodCall] call to method GenericM1 +# 100| -1: [LocalVariableAccess] access to local variable o +# 101| 3: [ExprStmt] ...; +# 101| 0: [MethodCall] call to method GenericM1 +# 101| -1: [LocalVariableAccess] access to local variable s +# 104| 4: [ExprStmt] ...; +# 104| 0: [MethodCall] call to method GenericM1 +# 104| -1: [TypeAccess] access to type MyExtensions +# 104| 0: [TypeMention] MyExtensions +# 104| 0: [LocalVariableAccess] access to local variable o +# 105| 5: [ExprStmt] ...; +# 105| 0: [MethodCall] call to method GenericM1 # 105| -1: [TypeAccess] access to type MyExtensions # 105| 0: [TypeMention] MyExtensions # 105| 0: [LocalVariableAccess] access to local variable s -# 105| 1: [StringLiteralUtf16] "test" -# 105| 2: [ObjectCreation] object creation of type Object -# 105| 0: [TypeMention] object +# 107| 6: [ExprStmt] ...; +# 107| 0: [MethodCall] call to method GenericM2 +# 107| -1: [LocalVariableAccess] access to local variable o +# 107| 0: [IntLiteral] 42 +# 108| 7: [ExprStmt] ...; +# 108| 0: [MethodCall] call to method GenericM2 +# 108| -1: [TypeAccess] access to type MyExtensions +# 108| 0: [TypeMention] MyExtensions +# 108| 0: [LocalVariableAccess] access to local variable o +# 108| 1: [IntLiteral] 42 +# 110| 8: [ExprStmt] ...; +# 110| 0: [MethodCall] call to method StringGenericM1 +# 110| -1: [LocalVariableAccess] access to local variable s +# 110| 0: [IntLiteral] 7 +# 110| 1: [ObjectCreation] object creation of type Object +# 110| 0: [TypeMention] object +# 111| 9: [ExprStmt] ...; +# 111| 0: [MethodCall] call to method StringGenericM1 +# 111| -1: [TypeAccess] access to type MyExtensions +# 111| 0: [TypeMention] MyExtensions +# 111| 0: [LocalVariableAccess] access to local variable s +# 111| 1: [StringLiteralUtf16] "test" +# 111| 2: [ObjectCreation] object creation of type Object +# 111| 0: [TypeMention] object diff --git a/csharp/ql/test/library-tests/extension/extensionTypes.expected b/csharp/ql/test/library-tests/extension/extensionTypes.expected index b27ff095a4b..30be52e8e89 100644 --- a/csharp/ql/test/library-tests/extension/extensionTypes.expected +++ b/csharp/ql/test/library-tests/extension/extensionTypes.expected @@ -5,10 +5,10 @@ extensionTypeReceiverParameter | extensionTypes.cs:18:5:21:5 | extension(Int32) | extensionTypes.cs:18:23:18:24 | i3 | | extensionTypes.cs:22:5:25:5 | extension(String) | extensionTypes.cs:22:23:22:23 | s | | extensionTypes.cs:26:5:29:5 | extension(T1)`1 | extensionTypes.cs:26:42:26:43 | t1 | -| extensions.cs:6:5:17:5 | extension(String) | extensions.cs:6:22:6:22 | s | -| extensions.cs:26:5:35:5 | extension(Object) | extensions.cs:26:20:26:20 | t | -| extensions.cs:26:5:35:5 | extension(String) | extensions.cs:26:20:26:20 | t | -| extensions.cs:26:5:35:5 | extension(T)`1 | extensions.cs:26:20:26:20 | t | +| extensions.cs:6:5:19:5 | extension(String) | extensions.cs:6:22:6:22 | s | +| extensions.cs:28:5:37:5 | extension(Object) | extensions.cs:28:20:28:20 | t | +| extensions.cs:28:5:37:5 | extension(String) | extensions.cs:28:20:28:20 | t | +| extensions.cs:28:5:37:5 | extension(T)`1 | extensions.cs:28:20:28:20 | t | extensionTypeExtendedType | extensionTypes.cs:6:5:9:5 | extension(String) | string | | extensionTypes.cs:10:5:13:5 | extension(Int32) | int | @@ -16,11 +16,11 @@ extensionTypeExtendedType | extensionTypes.cs:18:5:21:5 | extension(Int32) | int | | extensionTypes.cs:22:5:25:5 | extension(String) | string | | extensionTypes.cs:26:5:29:5 | extension(T1)`1 | T1 | -| extensions.cs:6:5:17:5 | extension(String) | string | -| extensions.cs:19:5:24:5 | extension(Object) | object | -| extensions.cs:26:5:35:5 | extension(Object) | object | -| extensions.cs:26:5:35:5 | extension(String) | string | -| extensions.cs:26:5:35:5 | extension(T)`1 | T | +| extensions.cs:6:5:19:5 | extension(String) | string | +| extensions.cs:21:5:26:5 | extension(Object) | object | +| extensions.cs:28:5:37:5 | extension(Object) | object | +| extensions.cs:28:5:37:5 | extension(String) | string | +| extensions.cs:28:5:37:5 | extension(T)`1 | T | extensionTypeReceiverParameterAttribute | extensionTypes.cs:6:5:9:5 | extension(String) | extensionTypes.cs:6:32:6:32 | s | extensionTypes.cs:6:16:6:22 | [NotNull(...)] | | extensionTypes.cs:26:5:29:5 | extension(T1)`1 | extensionTypes.cs:26:42:26:43 | t1 | extensionTypes.cs:26:20:26:30 | [NotNullWhen(...)] | @@ -30,7 +30,7 @@ extensionTypeReceiverParameterModifier | extensionTypes.cs:18:5:21:5 | extension(Int32) | extensionTypes.cs:18:23:18:24 | i3 | ref | extensionTypeParameterConstraints | extensionTypes.cs:26:5:29:5 | extension(T1)`1 | extensionTypes.cs:26:15:26:16 | T1 | file://:0:0:0:0 | where T1: ... | -| extensions.cs:26:5:35:5 | extension(T)`1 | extensions.cs:26:15:26:15 | T | file://:0:0:0:0 | where T: ... | +| extensions.cs:28:5:37:5 | extension(T)`1 | extensions.cs:28:15:28:15 | T | file://:0:0:0:0 | where T: ... | syntheticParameterModifier | extensionTypes.cs:10:5:13:5 | extension(Int32) | extensionTypes.cs:12:21:12:23 | M21 | extensionTypes.cs:10:32:10:33 | i1 | ref readonly | | extensionTypes.cs:14:5:17:5 | extension(Int32) | extensionTypes.cs:16:21:16:23 | M31 | extensionTypes.cs:14:22:14:23 | i2 | in | diff --git a/csharp/ql/test/library-tests/extension/extensions.cs b/csharp/ql/test/library-tests/extension/extensions.cs index 1117a98f8a0..892304ee84d 100644 --- a/csharp/ql/test/library-tests/extension/extensions.cs +++ b/csharp/ql/test/library-tests/extension/extensions.cs @@ -14,6 +14,8 @@ public static class MyExtensions public static int StaticM2(string x) { return x.Length; } public static string operator *(int a, string b) { return ""; } public T StringGenericM1(T t, object o) { return t; } + public void operator ++() { } + public static string operator --(string o) { return o; } } extension(object) @@ -61,8 +63,10 @@ public class C var x25 = object.StaticObjectM1(); var x26 = object.StaticObjectM2(s); - // Calling the extension operator. + // Calling the extension operators. var x30 = 3 * s; + s++; + s--; // Calling the classic extension method. var y = s.M3(); @@ -77,6 +81,8 @@ public class C // Calling the compiler generated operator method. MyExtensions.op_Multiply(3, s); + MyExtensions.op_IncrementAssignment(s); + MyExtensions.op_Decrement(s); // Calling the compiler generated methods used by the extension property accessors. MyExtensions.get_Prop1(s); diff --git a/csharp/ql/test/library-tests/extension/extensions.expected b/csharp/ql/test/library-tests/extension/extensions.expected index 45b557a9635..e29e455d25d 100644 --- a/csharp/ql/test/library-tests/extension/extensions.expected +++ b/csharp/ql/test/library-tests/extension/extensions.expected @@ -1,51 +1,51 @@ extensionMethodCallArgument -| extensions.cs:57:19:57:24 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:57:19:57:19 | access to local variable s | -| extensions.cs:58:19:58:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:58:19:58:19 | access to local variable s | -| extensions.cs:58:19:58:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:12:33:12:37 | other | 1 | extensions.cs:58:24:58:28 | "!!!" | -| extensions.cs:60:19:60:36 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:14:43:14:43 | x | 0 | extensions.cs:60:35:60:35 | access to local variable s | -| extensions.cs:62:19:62:42 | call to method StaticObjectM2 | extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:22:49:22:49 | s | 0 | extensions.cs:62:41:62:41 | access to local variable s | -| extensions.cs:68:17:68:22 | call to method M3 | extensions.cs:40:24:40:25 | M3 | extensions.cs:40:39:40:39 | s | 0 | extensions.cs:68:17:68:17 | access to local variable s | -| extensions.cs:71:9:71:26 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:71:25:71:25 | access to local variable s | -| extensions.cs:72:9:72:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:72:25:72:25 | access to local variable s | -| extensions.cs:72:9:72:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:12:33:12:37 | other | 1 | extensions.cs:72:28:72:32 | "!!!" | -| extensions.cs:74:9:74:32 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:14:43:14:43 | x | 0 | extensions.cs:74:31:74:31 | access to local variable s | -| extensions.cs:76:9:76:38 | call to method StaticObjectM2 | extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:22:49:22:49 | s | 0 | extensions.cs:76:37:76:37 | access to local variable s | -| extensions.cs:94:9:94:21 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:94:9:94:9 | access to local variable o | -| extensions.cs:95:9:95:21 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:95:9:95:9 | access to local variable s | -| extensions.cs:98:9:98:33 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:98:32:98:32 | access to local variable o | -| extensions.cs:99:9:99:33 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:99:32:99:32 | access to local variable s | -| extensions.cs:101:9:101:23 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:101:9:101:9 | access to local variable o | -| extensions.cs:101:9:101:23 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:31:36:31:40 | other | 1 | extensions.cs:101:21:101:22 | 42 | -| extensions.cs:102:9:102:37 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:20:26:20 | t | 0 | extensions.cs:102:32:102:32 | access to local variable o | -| extensions.cs:102:9:102:37 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:31:36:31:40 | other | 1 | extensions.cs:102:35:102:36 | 42 | -| extensions.cs:104:9:104:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:104:9:104:9 | access to local variable s | -| extensions.cs:104:9:104:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:39:16:39 | t | 1 | extensions.cs:104:32:104:32 | 7 | -| extensions.cs:104:9:104:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:49:16:49 | o | 2 | extensions.cs:104:35:104:46 | object creation of type Object | -| extensions.cs:105:9:105:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:105:46:105:46 | access to local variable s | -| extensions.cs:105:9:105:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:39:16:39 | t | 1 | extensions.cs:105:49:105:54 | "test" | -| extensions.cs:105:9:105:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:49:16:49 | o | 2 | extensions.cs:105:57:105:68 | object creation of type Object | +| extensions.cs:59:19:59:24 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:59:19:59:19 | access to local variable s | +| extensions.cs:60:19:60:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:60:19:60:19 | access to local variable s | +| extensions.cs:60:19:60:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:12:33:12:37 | other | 1 | extensions.cs:60:24:60:28 | "!!!" | +| extensions.cs:62:19:62:36 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:14:43:14:43 | x | 0 | extensions.cs:62:35:62:35 | access to local variable s | +| extensions.cs:64:19:64:42 | call to method StaticObjectM2 | extensions.cs:24:27:24:40 | StaticObjectM2 | extensions.cs:24:49:24:49 | s | 0 | extensions.cs:64:41:64:41 | access to local variable s | +| extensions.cs:72:17:72:22 | call to method M3 | extensions.cs:42:24:42:25 | M3 | extensions.cs:42:39:42:39 | s | 0 | extensions.cs:72:17:72:17 | access to local variable s | +| extensions.cs:75:9:75:26 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:75:25:75:25 | access to local variable s | +| extensions.cs:76:9:76:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:76:25:76:25 | access to local variable s | +| extensions.cs:76:9:76:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:12:33:12:37 | other | 1 | extensions.cs:76:28:76:32 | "!!!" | +| extensions.cs:78:9:78:32 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:14:43:14:43 | x | 0 | extensions.cs:78:31:78:31 | access to local variable s | +| extensions.cs:80:9:80:38 | call to method StaticObjectM2 | extensions.cs:24:27:24:40 | StaticObjectM2 | extensions.cs:24:49:24:49 | s | 0 | extensions.cs:80:37:80:37 | access to local variable s | +| extensions.cs:100:9:100:21 | call to method GenericM1 | extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:20:28:20 | t | 0 | extensions.cs:100:9:100:9 | access to local variable o | +| extensions.cs:101:9:101:21 | call to method GenericM1 | extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:20:28:20 | t | 0 | extensions.cs:101:9:101:9 | access to local variable s | +| extensions.cs:104:9:104:33 | call to method GenericM1 | extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:20:28:20 | t | 0 | extensions.cs:104:32:104:32 | access to local variable o | +| extensions.cs:105:9:105:33 | call to method GenericM1 | extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:20:28:20 | t | 0 | extensions.cs:105:32:105:32 | access to local variable s | +| extensions.cs:107:9:107:23 | call to method GenericM2 | extensions.cs:33:21:33:32 | GenericM2 | extensions.cs:28:20:28:20 | t | 0 | extensions.cs:107:9:107:9 | access to local variable o | +| extensions.cs:107:9:107:23 | call to method GenericM2 | extensions.cs:33:21:33:32 | GenericM2 | extensions.cs:33:36:33:40 | other | 1 | extensions.cs:107:21:107:22 | 42 | +| extensions.cs:108:9:108:37 | call to method GenericM2 | extensions.cs:33:21:33:32 | GenericM2 | extensions.cs:28:20:28:20 | t | 0 | extensions.cs:108:32:108:32 | access to local variable o | +| extensions.cs:108:9:108:37 | call to method GenericM2 | extensions.cs:33:21:33:32 | GenericM2 | extensions.cs:33:36:33:40 | other | 1 | extensions.cs:108:35:108:36 | 42 | +| extensions.cs:110:9:110:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:110:9:110:9 | access to local variable s | +| extensions.cs:110:9:110:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:39:16:39 | t | 1 | extensions.cs:110:32:110:32 | 7 | +| extensions.cs:110:9:110:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:49:16:49 | o | 2 | extensions.cs:110:35:110:46 | object creation of type Object | +| extensions.cs:111:9:111:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:111:46:111:46 | access to local variable s | +| extensions.cs:111:9:111:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:39:16:39 | t | 1 | extensions.cs:111:49:111:54 | "test" | +| extensions.cs:111:9:111:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:16:49:16:49 | o | 2 | extensions.cs:111:57:111:68 | object creation of type Object | extensionMethodCalls -| extensions.cs:57:19:57:24 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).M1 | -| extensions.cs:58:19:58:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).M2 | -| extensions.cs:59:19:59:35 | call to method StaticM1 | extensions.cs:13:27:13:34 | StaticM1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).StaticM1 | -| extensions.cs:60:19:60:36 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).StaticM2 | -| extensions.cs:61:19:61:41 | call to method StaticObjectM1 | extensions.cs:21:27:21:40 | StaticObjectM1 | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(System.Object).StaticObjectM1 | -| extensions.cs:62:19:62:42 | call to method StaticObjectM2 | extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(System.Object).StaticObjectM2 | -| extensions.cs:68:17:68:22 | call to method M3 | extensions.cs:40:24:40:25 | M3 | extensions.cs:38:21:38:37 | ClassicExtensions | ClassicExtensions.M3 | -| extensions.cs:71:9:71:26 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).M1 | -| extensions.cs:72:9:72:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).M2 | -| extensions.cs:73:9:73:31 | call to method StaticM1 | extensions.cs:13:27:13:34 | StaticM1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).StaticM1 | -| extensions.cs:74:9:74:32 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).StaticM2 | -| extensions.cs:75:9:75:37 | call to method StaticObjectM1 | extensions.cs:21:27:21:40 | StaticObjectM1 | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(System.Object).StaticObjectM1 | -| extensions.cs:76:9:76:38 | call to method StaticObjectM2 | extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(System.Object).StaticObjectM2 | -| extensions.cs:94:9:94:21 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:5:35:5 | extension(Object) | MyExtensions+extension(System.Object).GenericM1 | -| extensions.cs:95:9:95:21 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:5:35:5 | extension(String) | MyExtensions+extension(System.String).GenericM1 | -| extensions.cs:98:9:98:33 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:5:35:5 | extension(Object) | MyExtensions+extension(System.Object).GenericM1 | -| extensions.cs:99:9:99:33 | call to method GenericM1 | extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:5:35:5 | extension(String) | MyExtensions+extension(System.String).GenericM1 | -| extensions.cs:101:9:101:23 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:5:35:5 | extension(Object) | MyExtensions+extension(System.Object).GenericM2 | -| extensions.cs:102:9:102:37 | call to method GenericM2 | extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:5:35:5 | extension(Object) | MyExtensions+extension(System.Object).GenericM2 | -| extensions.cs:104:9:104:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).StringGenericM1 | -| extensions.cs:105:9:105:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).StringGenericM1 | +| extensions.cs:59:19:59:24 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).M1 | +| extensions.cs:60:19:60:29 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).M2 | +| extensions.cs:61:19:61:35 | call to method StaticM1 | extensions.cs:13:27:13:34 | StaticM1 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).StaticM1 | +| extensions.cs:62:19:62:36 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).StaticM2 | +| extensions.cs:63:19:63:41 | call to method StaticObjectM1 | extensions.cs:23:27:23:40 | StaticObjectM1 | extensions.cs:21:5:26:5 | extension(Object) | MyExtensions+extension(System.Object).StaticObjectM1 | +| extensions.cs:64:19:64:42 | call to method StaticObjectM2 | extensions.cs:24:27:24:40 | StaticObjectM2 | extensions.cs:21:5:26:5 | extension(Object) | MyExtensions+extension(System.Object).StaticObjectM2 | +| extensions.cs:72:17:72:22 | call to method M3 | extensions.cs:42:24:42:25 | M3 | extensions.cs:40:21:40:37 | ClassicExtensions | ClassicExtensions.M3 | +| extensions.cs:75:9:75:26 | call to method M1 | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).M1 | +| extensions.cs:76:9:76:33 | call to method M2 | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).M2 | +| extensions.cs:77:9:77:31 | call to method StaticM1 | extensions.cs:13:27:13:34 | StaticM1 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).StaticM1 | +| extensions.cs:78:9:78:32 | call to method StaticM2 | extensions.cs:14:27:14:34 | StaticM2 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).StaticM2 | +| extensions.cs:79:9:79:37 | call to method StaticObjectM1 | extensions.cs:23:27:23:40 | StaticObjectM1 | extensions.cs:21:5:26:5 | extension(Object) | MyExtensions+extension(System.Object).StaticObjectM1 | +| extensions.cs:80:9:80:38 | call to method StaticObjectM2 | extensions.cs:24:27:24:40 | StaticObjectM2 | extensions.cs:21:5:26:5 | extension(Object) | MyExtensions+extension(System.Object).StaticObjectM2 | +| extensions.cs:100:9:100:21 | call to method GenericM1 | extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:5:37:5 | extension(Object) | MyExtensions+extension(System.Object).GenericM1 | +| extensions.cs:101:9:101:21 | call to method GenericM1 | extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:5:37:5 | extension(String) | MyExtensions+extension(System.String).GenericM1 | +| extensions.cs:104:9:104:33 | call to method GenericM1 | extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:5:37:5 | extension(Object) | MyExtensions+extension(System.Object).GenericM1 | +| extensions.cs:105:9:105:33 | call to method GenericM1 | extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:5:37:5 | extension(String) | MyExtensions+extension(System.String).GenericM1 | +| extensions.cs:107:9:107:23 | call to method GenericM2 | extensions.cs:33:21:33:32 | GenericM2 | extensions.cs:28:5:37:5 | extension(Object) | MyExtensions+extension(System.Object).GenericM2 | +| extensions.cs:108:9:108:37 | call to method GenericM2 | extensions.cs:33:21:33:32 | GenericM2 | extensions.cs:28:5:37:5 | extension(Object) | MyExtensions+extension(System.Object).GenericM2 | +| extensions.cs:110:9:110:47 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).StringGenericM1 | +| extensions.cs:111:9:111:69 | call to method StringGenericM1 | extensions.cs:16:18:16:35 | StringGenericM1 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).StringGenericM1 | extensionParameter | extensions.cs:11:21:11:22 | M1 | extensions.cs:6:22:6:22 | s | 0 | string | extensions.cs:6:22:6:22 | s | | extensions.cs:12:23:12:24 | M2 | extensions.cs:6:22:6:22 | s | 0 | string | extensions.cs:6:22:6:22 | s | @@ -60,52 +60,60 @@ extensionParameter | extensions.cs:16:18:16:35 | StringGenericM1`1 | extensions.cs:6:22:6:22 | s | 0 | string | extensions.cs:6:22:6:22 | s | | extensions.cs:16:18:16:35 | StringGenericM1`1 | extensions.cs:16:39:16:39 | t | 1 | T | extensions.cs:16:39:16:39 | t | | extensions.cs:16:18:16:35 | StringGenericM1`1 | extensions.cs:16:49:16:49 | o | 2 | object | extensions.cs:16:49:16:49 | o | -| extensions.cs:22:27:22:40 | StaticObjectM2 | extensions.cs:22:49:22:49 | s | 0 | string | extensions.cs:22:49:22:49 | s | -| extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | T | extensions.cs:26:20:26:20 | t | -| extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | object | extensions.cs:26:20:26:20 | t | -| extensions.cs:30:21:30:29 | GenericM1 | extensions.cs:26:20:26:20 | t | 0 | string | extensions.cs:26:20:26:20 | t | -| extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:26:20:26:20 | t | 0 | object | extensions.cs:26:20:26:20 | t | -| extensions.cs:31:21:31:32 | GenericM2 | extensions.cs:31:36:31:40 | other | 1 | int | extensions.cs:31:36:31:40 | other | -| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:26:20:26:20 | t | 0 | T | extensions.cs:26:20:26:20 | t | -| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:26:20:26:20 | t | 0 | object | extensions.cs:26:20:26:20 | t | -| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:26:20:26:20 | t | 0 | string | extensions.cs:26:20:26:20 | t | -| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:31:36:31:40 | other | 1 | S | extensions.cs:31:36:31:40 | other | -| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:31:36:31:40 | other | 1 | S | extensions.cs:31:36:31:40 | other | -| extensions.cs:31:21:31:32 | GenericM2`1 | extensions.cs:31:36:31:40 | other | 1 | S | extensions.cs:31:36:31:40 | other | -| extensions.cs:32:21:32:35 | GenericStaticM1 | extensions.cs:26:20:26:20 | t | 0 | T | extensions.cs:26:20:26:20 | t | -| extensions.cs:32:21:32:35 | GenericStaticM1 | extensions.cs:26:20:26:20 | t | 0 | object | extensions.cs:26:20:26:20 | t | -| extensions.cs:32:21:32:35 | GenericStaticM1 | extensions.cs:26:20:26:20 | t | 0 | string | extensions.cs:26:20:26:20 | t | -| extensions.cs:33:28:33:45 | GenericStaticM2`1 | extensions.cs:33:49:33:53 | other | 0 | S | extensions.cs:33:49:33:53 | other | -| extensions.cs:33:28:33:45 | GenericStaticM2`1 | extensions.cs:33:49:33:53 | other | 0 | S | extensions.cs:33:49:33:53 | other | -| extensions.cs:33:28:33:45 | GenericStaticM2`1 | extensions.cs:33:49:33:53 | other | 0 | S | extensions.cs:33:49:33:53 | other | -| extensions.cs:40:24:40:25 | M3 | extensions.cs:40:39:40:39 | s | 0 | string | extensions.cs:40:39:40:39 | s | +| extensions.cs:24:27:24:40 | StaticObjectM2 | extensions.cs:24:49:24:49 | s | 0 | string | extensions.cs:24:49:24:49 | s | +| extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:20:28:20 | t | 0 | T | extensions.cs:28:20:28:20 | t | +| extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:20:28:20 | t | 0 | object | extensions.cs:28:20:28:20 | t | +| extensions.cs:32:21:32:29 | GenericM1 | extensions.cs:28:20:28:20 | t | 0 | string | extensions.cs:28:20:28:20 | t | +| extensions.cs:33:21:33:32 | GenericM2 | extensions.cs:28:20:28:20 | t | 0 | object | extensions.cs:28:20:28:20 | t | +| extensions.cs:33:21:33:32 | GenericM2 | extensions.cs:33:36:33:40 | other | 1 | int | extensions.cs:33:36:33:40 | other | +| extensions.cs:33:21:33:32 | GenericM2`1 | extensions.cs:28:20:28:20 | t | 0 | T | extensions.cs:28:20:28:20 | t | +| extensions.cs:33:21:33:32 | GenericM2`1 | extensions.cs:28:20:28:20 | t | 0 | object | extensions.cs:28:20:28:20 | t | +| extensions.cs:33:21:33:32 | GenericM2`1 | extensions.cs:28:20:28:20 | t | 0 | string | extensions.cs:28:20:28:20 | t | +| extensions.cs:33:21:33:32 | GenericM2`1 | extensions.cs:33:36:33:40 | other | 1 | S | extensions.cs:33:36:33:40 | other | +| extensions.cs:33:21:33:32 | GenericM2`1 | extensions.cs:33:36:33:40 | other | 1 | S | extensions.cs:33:36:33:40 | other | +| extensions.cs:33:21:33:32 | GenericM2`1 | extensions.cs:33:36:33:40 | other | 1 | S | extensions.cs:33:36:33:40 | other | +| extensions.cs:34:21:34:35 | GenericStaticM1 | extensions.cs:28:20:28:20 | t | 0 | T | extensions.cs:28:20:28:20 | t | +| extensions.cs:34:21:34:35 | GenericStaticM1 | extensions.cs:28:20:28:20 | t | 0 | object | extensions.cs:28:20:28:20 | t | +| extensions.cs:34:21:34:35 | GenericStaticM1 | extensions.cs:28:20:28:20 | t | 0 | string | extensions.cs:28:20:28:20 | t | +| extensions.cs:35:28:35:45 | GenericStaticM2`1 | extensions.cs:35:49:35:53 | other | 0 | S | extensions.cs:35:49:35:53 | other | +| extensions.cs:35:28:35:45 | GenericStaticM2`1 | extensions.cs:35:49:35:53 | other | 0 | S | extensions.cs:35:49:35:53 | other | +| extensions.cs:35:28:35:45 | GenericStaticM2`1 | extensions.cs:35:49:35:53 | other | 0 | S | extensions.cs:35:49:35:53 | other | +| extensions.cs:42:24:42:25 | M3 | extensions.cs:42:39:42:39 | s | 0 | string | extensions.cs:42:39:42:39 | s | extensionOperatorCallArgument -| extensions.cs:15:39:15:39 | * | extensions.cs:65:19:65:23 | call to operator * | extensions.cs:15:45:15:45 | a | 0 | extensions.cs:65:19:65:19 | 3 | -| extensions.cs:15:39:15:39 | * | extensions.cs:65:19:65:23 | call to operator * | extensions.cs:15:55:15:55 | b | 1 | extensions.cs:65:23:65:23 | access to local variable s | -| extensions.cs:15:39:15:39 | * | extensions.cs:79:9:79:38 | call to operator * | extensions.cs:15:45:15:45 | a | 0 | extensions.cs:79:34:79:34 | 3 | -| extensions.cs:15:39:15:39 | * | extensions.cs:79:9:79:38 | call to operator * | extensions.cs:15:55:15:55 | b | 1 | extensions.cs:79:37:79:37 | access to local variable s | +| extensions.cs:15:39:15:39 | * | extensions.cs:67:19:67:23 | call to operator * | extensions.cs:15:45:15:45 | a | 0 | extensions.cs:67:19:67:19 | 3 | +| extensions.cs:15:39:15:39 | * | extensions.cs:67:19:67:23 | call to operator * | extensions.cs:15:55:15:55 | b | 1 | extensions.cs:67:23:67:23 | access to local variable s | +| extensions.cs:15:39:15:39 | * | extensions.cs:83:9:83:38 | call to operator * | extensions.cs:15:45:15:45 | a | 0 | extensions.cs:83:34:83:34 | 3 | +| extensions.cs:15:39:15:39 | * | extensions.cs:83:9:83:38 | call to operator * | extensions.cs:15:55:15:55 | b | 1 | extensions.cs:83:37:83:37 | access to local variable s | +| extensions.cs:17:30:17:31 | ++ | extensions.cs:68:9:68:11 | call to operator ++ | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:68:9:68:9 | access to local variable s | +| extensions.cs:17:30:17:31 | ++ | extensions.cs:84:9:84:46 | call to operator ++ | extensions.cs:6:22:6:22 | s | 0 | extensions.cs:84:45:84:45 | access to local variable s | +| extensions.cs:18:39:18:40 | -- | extensions.cs:69:9:69:11 | call to operator -- | extensions.cs:18:49:18:49 | o | 0 | extensions.cs:69:9:69:9 | access to local variable s | +| extensions.cs:18:39:18:40 | -- | extensions.cs:85:9:85:36 | call to operator -- | extensions.cs:18:49:18:49 | o | 0 | extensions.cs:85:35:85:35 | access to local variable s | extensionOperatorCalls -| extensions.cs:65:19:65:23 | call to operator * | extensions.cs:15:39:15:39 | * | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).op_Multiply | -| extensions.cs:79:9:79:38 | call to operator * | extensions.cs:15:39:15:39 | * | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).op_Multiply | +| extensions.cs:67:19:67:23 | call to operator * | extensions.cs:15:39:15:39 | * | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).op_Multiply | +| extensions.cs:68:9:68:11 | call to operator ++ | extensions.cs:17:30:17:31 | ++ | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).op_IncrementAssignment | +| extensions.cs:69:9:69:11 | call to operator -- | extensions.cs:18:39:18:40 | -- | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).op_Decrement | +| extensions.cs:83:9:83:38 | call to operator * | extensions.cs:15:39:15:39 | * | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).op_Multiply | +| extensions.cs:84:9:84:46 | call to operator ++ | extensions.cs:17:30:17:31 | ++ | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).op_IncrementAssignment | +| extensions.cs:85:9:85:36 | call to operator -- | extensions.cs:18:39:18:40 | -- | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).op_Decrement | extensionProperty -| extensions.cs:8:21:8:25 | Prop1 | extensions.cs:6:5:17:5 | extension(String) | -| extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:17:5 | extension(String) | -| extensions.cs:10:28:10:38 | StaticProp1 | extensions.cs:6:5:17:5 | extension(String) | -| extensions.cs:23:28:23:37 | StaticProp | extensions.cs:19:5:24:5 | extension(Object) | -| extensions.cs:28:21:28:32 | GenericProp1 | extensions.cs:26:5:35:5 | extension(Object) | -| extensions.cs:28:21:28:32 | GenericProp1 | extensions.cs:26:5:35:5 | extension(String) | -| extensions.cs:28:21:28:32 | GenericProp1 | extensions.cs:26:5:35:5 | extension(T)`1 | -| extensions.cs:29:21:29:32 | GenericProp2 | extensions.cs:26:5:35:5 | extension(Object) | -| extensions.cs:29:21:29:32 | GenericProp2 | extensions.cs:26:5:35:5 | extension(String) | -| extensions.cs:29:21:29:32 | GenericProp2 | extensions.cs:26:5:35:5 | extension(T)`1 | +| extensions.cs:8:21:8:25 | Prop1 | extensions.cs:6:5:19:5 | extension(String) | +| extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:19:5 | extension(String) | +| extensions.cs:10:28:10:38 | StaticProp1 | extensions.cs:6:5:19:5 | extension(String) | +| extensions.cs:25:28:25:37 | StaticProp | extensions.cs:21:5:26:5 | extension(Object) | +| extensions.cs:30:21:30:32 | GenericProp1 | extensions.cs:28:5:37:5 | extension(Object) | +| extensions.cs:30:21:30:32 | GenericProp1 | extensions.cs:28:5:37:5 | extension(String) | +| extensions.cs:30:21:30:32 | GenericProp1 | extensions.cs:28:5:37:5 | extension(T)`1 | +| extensions.cs:31:21:31:32 | GenericProp2 | extensions.cs:28:5:37:5 | extension(Object) | +| extensions.cs:31:21:31:32 | GenericProp2 | extensions.cs:28:5:37:5 | extension(String) | +| extensions.cs:31:21:31:32 | GenericProp2 | extensions.cs:28:5:37:5 | extension(T)`1 | extensionPropertyCall -| extensions.cs:50:19:50:25 | access to property Prop1 | extensions.cs:8:21:8:25 | Prop1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).Prop1 | -| extensions.cs:51:19:51:25 | access to property Prop2 | extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).Prop2 | -| extensions.cs:52:9:52:15 | access to property Prop2 | extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).Prop2 | -| extensions.cs:53:19:53:36 | access to property StaticProp1 | extensions.cs:10:28:10:38 | StaticProp1 | extensions.cs:6:5:17:5 | extension(String) | MyExtensions+extension(System.String).StaticProp1 | -| extensions.cs:54:19:54:35 | access to property StaticProp | extensions.cs:23:28:23:37 | StaticProp | extensions.cs:19:5:24:5 | extension(Object) | MyExtensions+extension(System.Object).StaticProp | +| extensions.cs:52:19:52:25 | access to property Prop1 | extensions.cs:8:21:8:25 | Prop1 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).Prop1 | +| extensions.cs:53:19:53:25 | access to property Prop2 | extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).Prop2 | +| extensions.cs:54:9:54:15 | access to property Prop2 | extensions.cs:9:21:9:25 | Prop2 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).Prop2 | +| extensions.cs:55:19:55:36 | access to property StaticProp1 | extensions.cs:10:28:10:38 | StaticProp1 | extensions.cs:6:5:19:5 | extension(String) | MyExtensions+extension(System.String).StaticProp1 | +| extensions.cs:56:19:56:35 | access to property StaticProp | extensions.cs:25:28:25:37 | StaticProp | extensions.cs:21:5:26:5 | extension(Object) | MyExtensions+extension(System.Object).StaticProp | extensionAccessorCall -| extensions.cs:82:9:82:33 | call to extension accessor get_Prop1 | extensions.cs:8:30:8:41 | get_Prop1 | extensions.cs:8:21:8:25 | Prop1 | MyExtensions+extension(System.String).get_Prop1 | -| extensions.cs:83:9:83:33 | call to extension accessor get_Prop2 | extensions.cs:9:29:9:31 | get_Prop2 | extensions.cs:9:21:9:25 | Prop2 | MyExtensions+extension(System.String).get_Prop2 | -| extensions.cs:84:9:84:40 | call to extension accessor set_Prop2 | extensions.cs:9:50:9:52 | set_Prop2 | extensions.cs:9:21:9:25 | Prop2 | MyExtensions+extension(System.String).set_Prop2 | -| extensions.cs:85:9:85:37 | call to extension accessor get_StaticProp | extensions.cs:23:42:23:45 | get_StaticProp | extensions.cs:23:28:23:37 | StaticProp | MyExtensions+extension(System.Object).get_StaticProp | +| extensions.cs:88:9:88:33 | call to extension accessor get_Prop1 | extensions.cs:8:30:8:41 | get_Prop1 | extensions.cs:8:21:8:25 | Prop1 | MyExtensions+extension(System.String).get_Prop1 | +| extensions.cs:89:9:89:33 | call to extension accessor get_Prop2 | extensions.cs:9:29:9:31 | get_Prop2 | extensions.cs:9:21:9:25 | Prop2 | MyExtensions+extension(System.String).get_Prop2 | +| extensions.cs:90:9:90:40 | call to extension accessor set_Prop2 | extensions.cs:9:50:9:52 | set_Prop2 | extensions.cs:9:21:9:25 | Prop2 | MyExtensions+extension(System.String).set_Prop2 | +| extensions.cs:91:9:91:37 | call to extension accessor get_StaticProp | extensions.cs:25:42:25:45 | get_StaticProp | extensions.cs:25:28:25:37 | StaticProp | MyExtensions+extension(System.Object).get_StaticProp | From 27e6b5c0fa033bd8c713da02d4b40b870475cb60 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 11 May 2026 15:08:06 +0200 Subject: [PATCH 24/36] C#: Introduce a class for instance mutator operator calls. --- .../ql/lib/semmle/code/csharp/exprs/Call.qll | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll index 9dbf898e286..2ecbbc44a4d 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll @@ -570,6 +570,29 @@ class MutatorOperatorCall extends OperatorCall { predicate isPostfix() { mutator_invocation_mode(this, 2) } } +/** + * A call to an instance mutator operator, for example `a++` on + * line 5 in + * + * ```csharp + * class A { + * public void operator++() { ... } + * + * public static void Increment(A a) { + * a++; + * } + * } + * ``` + */ +class InstanceMutatorOperatorCall extends MutatorOperatorCall { + InstanceMutatorOperatorCall() { this.getTarget().getNumberOfParameters() = 0 } + + /** Gets the qualifier of this instance mutator operator call. */ + Expr getQualifier() { result = this.getChildExpr(0) } + + override Expr getArgument(int i) { none() } +} + /** * A call to a compound assignment operator, for example `this += other` * on line 7 in From 0c3ab803ef9da3eacfef5208d66839f713f01d2a Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 11 May 2026 15:08:56 +0200 Subject: [PATCH 25/36] C#: Update the dispatch logic to account for all instance operator calls. --- .../semmle/code/csharp/dispatch/Dispatch.qll | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index 15a64d12b49..f1df963d72b 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -73,6 +73,19 @@ class DispatchCall extends Internal::TDispatchCall { } } +abstract private class InstanceOperatorCall extends OperatorCall { + abstract Expr getQualifier(); +} + +private class InstanceCompoundAssignment extends InstanceOperatorCall instanceof CompoundAssignmentOperatorCall +{ + override Expr getQualifier() { result = CompoundAssignmentOperatorCall.super.getQualifier() } +} + +private class InstanceMutator extends InstanceOperatorCall instanceof InstanceMutatorOperatorCall { + override Expr getQualifier() { result = InstanceMutatorOperatorCall.super.getQualifier() } +} + /** Internal implementation details. */ private module Internal { private import OverridableCallable @@ -101,9 +114,9 @@ private module Internal { } or TDispatchOperatorCall(OperatorCall oc) { not oc.isLateBound() and - not oc instanceof CompoundAssignmentOperatorCall + not oc instanceof InstanceOperatorCall } or - TDispatchCompoundAssignmentOperatorCall(CompoundAssignmentOperatorCall caoc) or + TDispatchInstanceOperatorCall(InstanceOperatorCall caoc) or TDispatchReflectionCall(MethodCall mc, string name, Expr object, Expr qualifier, int args) { isReflectionCall(mc, name, object, qualifier, args) } or @@ -890,12 +903,10 @@ private module Internal { override Operator getAStaticTarget() { result = this.getCall().getTarget() } } - private class DispatchCompoundAssignmentOperatorCall extends DispatchOverridableCall, - TDispatchCompoundAssignmentOperatorCall + private class DispatchInstanceOperatorCall extends DispatchOverridableCall, + TDispatchInstanceOperatorCall { - override CompoundAssignmentOperatorCall getCall() { - this = TDispatchCompoundAssignmentOperatorCall(result) - } + override InstanceOperatorCall getCall() { this = TDispatchInstanceOperatorCall(result) } override Expr getArgument(int i) { result = this.getCall().getArgument(i) } From 4bd9005f9a65cc401a90569f6f87bb40ca22ee1f Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Mon, 11 May 2026 15:12:34 +0200 Subject: [PATCH 26/36] C#: Add data flow testcases for mutation operators. --- .../dataflow/operators/Operator.cs | 33 +++++++++++++++++++ .../dataflow/operators/operatorFlow.expected | 24 ++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/csharp/ql/test/library-tests/dataflow/operators/Operator.cs b/csharp/ql/test/library-tests/dataflow/operators/Operator.cs index 5db1a82b9a4..0b6aa2e8f90 100644 --- a/csharp/ql/test/library-tests/dataflow/operators/Operator.cs +++ b/csharp/ql/test/library-tests/dataflow/operators/Operator.cs @@ -120,3 +120,36 @@ public class CompoundAssignmentOperators Sink(x.Field); // $ hasValueFlow=1 } } + +public class MutatorOperators +{ + static void Sink(object o) { } + static T Source(object source) => throw null; + + public class C1 + { + public object Field { get; private set; } + + public C1() + { + Field = new object(); + } + + public C1(object o) + { + Field = o; + } + + public void operator ++() + { + Field = Source(1); + } + + public void M1() + { + var x = new C1(); + x++; + Sink(x.Field); // $ hasValueFlow=1 + } + } +} diff --git a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected index 8fd12f1c2a8..dc1ec8b71f4 100644 --- a/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected +++ b/csharp/ql/test/library-tests/dataflow/operators/operatorFlow.expected @@ -130,6 +130,16 @@ edges | Operator.cs:119:14:119:14 | access to local variable y : C [property Field] : Object | Operator.cs:119:9:119:9 | [post] access to local variable x : C [property Field] : Object | provenance | | | Operator.cs:120:14:120:14 | access to local variable x : C [property Field] : Object | Operator.cs:120:14:120:20 | access to property Field | provenance | | | Operator.cs:120:14:120:14 | access to local variable x : C [property Field] : Object | Operator.cs:120:14:120:20 | access to property Field | provenance | | +| Operator.cs:143:30:143:31 | this [Return] : C1 [property Field] : Object | Operator.cs:151:13:151:13 | [post] access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:143:30:143:31 | this [Return] : C1 [property Field] : Object | Operator.cs:151:13:151:13 | [post] access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:145:13:145:17 | [post] this access : C1 [property Field] : Object | Operator.cs:143:30:143:31 | this [Return] : C1 [property Field] : Object | provenance | | +| Operator.cs:145:13:145:17 | [post] this access : C1 [property Field] : Object | Operator.cs:143:30:143:31 | this [Return] : C1 [property Field] : Object | provenance | | +| Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:145:13:145:17 | [post] this access : C1 [property Field] : Object | provenance | | +| Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:145:13:145:17 | [post] this access : C1 [property Field] : Object | provenance | | +| Operator.cs:151:13:151:13 | [post] access to local variable x : C1 [property Field] : Object | Operator.cs:152:18:152:18 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:151:13:151:13 | [post] access to local variable x : C1 [property Field] : Object | Operator.cs:152:18:152:18 | access to local variable x : C1 [property Field] : Object | provenance | | +| Operator.cs:152:18:152:18 | access to local variable x : C1 [property Field] : Object | Operator.cs:152:18:152:24 | access to property Field | provenance | | +| Operator.cs:152:18:152:18 | access to local variable x : C1 [property Field] : Object | Operator.cs:152:18:152:24 | access to property Field | provenance | | nodes | Operator.cs:9:39:9:39 | x : C | semmle.label | x : C | | Operator.cs:9:39:9:39 | x : C | semmle.label | x : C | @@ -275,6 +285,18 @@ nodes | Operator.cs:120:14:120:14 | access to local variable x : C [property Field] : Object | semmle.label | access to local variable x : C [property Field] : Object | | Operator.cs:120:14:120:20 | access to property Field | semmle.label | access to property Field | | Operator.cs:120:14:120:20 | access to property Field | semmle.label | access to property Field | +| Operator.cs:143:30:143:31 | this [Return] : C1 [property Field] : Object | semmle.label | this [Return] : C1 [property Field] : Object | +| Operator.cs:143:30:143:31 | this [Return] : C1 [property Field] : Object | semmle.label | this [Return] : C1 [property Field] : Object | +| Operator.cs:145:13:145:17 | [post] this access : C1 [property Field] : Object | semmle.label | [post] this access : C1 [property Field] : Object | +| Operator.cs:145:13:145:17 | [post] this access : C1 [property Field] : Object | semmle.label | [post] this access : C1 [property Field] : Object | +| Operator.cs:145:21:145:37 | call to method Source : Object | semmle.label | call to method Source : Object | +| Operator.cs:145:21:145:37 | call to method Source : Object | semmle.label | call to method Source : Object | +| Operator.cs:151:13:151:13 | [post] access to local variable x : C1 [property Field] : Object | semmle.label | [post] access to local variable x : C1 [property Field] : Object | +| Operator.cs:151:13:151:13 | [post] access to local variable x : C1 [property Field] : Object | semmle.label | [post] access to local variable x : C1 [property Field] : Object | +| Operator.cs:152:18:152:18 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:152:18:152:18 | access to local variable x : C1 [property Field] : Object | semmle.label | access to local variable x : C1 [property Field] : Object | +| Operator.cs:152:18:152:24 | access to property Field | semmle.label | access to property Field | +| Operator.cs:152:18:152:24 | access to property Field | semmle.label | access to property Field | subpaths | Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:16:38:16:38 | x : C | Operator.cs:16:49:16:49 | access to parameter x : C | Operator.cs:29:17:29:21 | call to operator + : C | | Operator.cs:29:17:29:17 | access to local variable x : C | Operator.cs:16:38:16:38 | x : C | Operator.cs:16:49:16:49 | access to parameter x : C | Operator.cs:29:17:29:21 | call to operator + : C | @@ -308,3 +330,5 @@ testFailures | Operator.cs:78:14:78:14 | (...) ... | Operator.cs:84:17:84:29 | call to method Source : C | Operator.cs:78:14:78:14 | (...) ... | $@ | Operator.cs:84:17:84:29 | call to method Source : C | call to method Source : C | | Operator.cs:120:14:120:20 | access to property Field | Operator.cs:116:23:116:39 | call to method Source : Object | Operator.cs:120:14:120:20 | access to property Field | $@ | Operator.cs:116:23:116:39 | call to method Source : Object | call to method Source : Object | | Operator.cs:120:14:120:20 | access to property Field | Operator.cs:116:23:116:39 | call to method Source : Object | Operator.cs:120:14:120:20 | access to property Field | $@ | Operator.cs:116:23:116:39 | call to method Source : Object | call to method Source : Object | +| Operator.cs:152:18:152:24 | access to property Field | Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:152:18:152:24 | access to property Field | $@ | Operator.cs:145:21:145:37 | call to method Source : Object | call to method Source : Object | +| Operator.cs:152:18:152:24 | access to property Field | Operator.cs:145:21:145:37 | call to method Source : Object | Operator.cs:152:18:152:24 | access to property Field | $@ | Operator.cs:145:21:145:37 | call to method Source : Object | call to method Source : Object | From 5ed3014f7d27ad220510906a748e1621faf77753 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 12 May 2026 14:20:48 +0200 Subject: [PATCH 27/36] C#: Add change-note. --- .../lib/change-notes/2026-05-12-user-increment-decrement.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 csharp/ql/lib/change-notes/2026-05-12-user-increment-decrement.md diff --git a/csharp/ql/lib/change-notes/2026-05-12-user-increment-decrement.md b/csharp/ql/lib/change-notes/2026-05-12-user-increment-decrement.md new file mode 100644 index 00000000000..a840fdf4fe3 --- /dev/null +++ b/csharp/ql/lib/change-notes/2026-05-12-user-increment-decrement.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* C# 14: Added support for user-defined instance increment/decrement operators. From fa2d6335969a84e85c2acadd5f255ae534819b62 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Wed, 13 May 2026 09:22:31 +0200 Subject: [PATCH 28/36] C#: Address co-pilot review comments. --- .../Semmle.Extraction.CSharp.Util/SymbolExtensions.cs | 6 +++--- csharp/ql/lib/semmle/code/csharp/exprs/Call.qll | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs b/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs index 50604e2404e..8106cfbf233 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Util/SymbolExtensions.cs @@ -53,11 +53,11 @@ namespace Semmle.Extraction.CSharp.Util }); /// - /// The operatorname for user-defined increment and decrement operators are "op_IncrementAssignment" and + /// The operatorname for user-defined instance increment- and decrement operators are "op_IncrementAssignment" and /// "op_DecrementAssignment" respectively. /// Thus we need to handle this explicitly to avoid postfixing them with an "=". /// - private static bool isIncrementOrDecrement(string operatorName) => operatorName == "++" || operatorName == "--"; + private static bool IsIncrementOrDecrement(string operatorName) => operatorName == "++" || operatorName == "--"; /// /// Convert an operator method name in to a symbolic name. @@ -79,7 +79,7 @@ namespace Semmle.Extraction.CSharp.Util if (match.Success && methodToOperator.TryGetValue($"op_{match.Groups[2]}", out var rawOperatorName)) { var prefix = match.Groups[1].Success ? "checked " : ""; - var postfix = match.Groups[3].Success && !isIncrementOrDecrement(rawOperatorName) ? "=" : ""; + var postfix = match.Groups[3].Success && !IsIncrementOrDecrement(rawOperatorName) ? "=" : ""; operatorName = $"{prefix}{rawOperatorName}{postfix}"; return true; } diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll index 2ecbbc44a4d..c9b8e61f493 100644 --- a/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll +++ b/csharp/ql/lib/semmle/code/csharp/exprs/Call.qll @@ -576,7 +576,7 @@ class MutatorOperatorCall extends OperatorCall { * * ```csharp * class A { - * public void operator++() { ... } + * public void operator ++() { ... } * * public static void Increment(A a) { * a++; From d28792537baff2f8d454ac02bf19c7823f1bef94 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 13 May 2026 10:32:05 +0200 Subject: [PATCH 29/36] Python extractor: use relative paths in diagnostic locations Diagnostic `Location.file` fields contained absolute filesystem paths, causing the GitHub UI to generate broken file links with runner paths like `/home/runner/work/...`. Now paths are relativized against the source root (`LGTM_SRC` or cwd), falling back to absolute if the file is outside the source root. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../writing-diagnostics/diagnostics.expected | 14 ++++++------ python/extractor/semmle/logging.py | 22 +++++++++++++++---- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/python/extractor/cli-integration-test/writing-diagnostics/diagnostics.expected b/python/extractor/cli-integration-test/writing-diagnostics/diagnostics.expected index de218a50e1e..12a241ad7b6 100644 --- a/python/extractor/cli-integration-test/writing-diagnostics/diagnostics.expected +++ b/python/extractor/cli-integration-test/writing-diagnostics/diagnostics.expected @@ -17,13 +17,13 @@ ] }, "location": { - "file": "/repo_dir/syntaxerror3.py", + "file": "syntaxerror3.py", "startColumn": 0, "endColumn": 0, "startLine": 1, "endLine": 1 }, - "markdownMessage": "A parse error occurred while processing `/repo_dir/syntaxerror3.py`, and as a result this file could not be analyzed. Check the syntax of the file using the `python -m py_compile` command and correct any invalid syntax.", + "markdownMessage": "A parse error occurred while processing `syntaxerror3.py`, and as a result this file could not be analyzed. Check the syntax of the file using the `python -m py_compile` command and correct any invalid syntax.", "severity": "warning", "source": { "extractorName": "python", @@ -56,13 +56,13 @@ ] }, "location": { - "file": "/repo_dir/syntaxerror1.py", + "file": "syntaxerror1.py", "startColumn": 0, "endColumn": 0, "startLine": 3, "endLine": 3 }, - "markdownMessage": "A parse error occurred while processing `/repo_dir/syntaxerror1.py`, and as a result this file could not be analyzed. Check the syntax of the file using the `python -m py_compile` command and correct any invalid syntax.", + "markdownMessage": "A parse error occurred while processing `syntaxerror1.py`, and as a result this file could not be analyzed. Check the syntax of the file using the `python -m py_compile` command and correct any invalid syntax.", "severity": "warning", "source": { "extractorName": "python", @@ -95,13 +95,13 @@ ] }, "location": { - "file": "/repo_dir/syntaxerror2.py", + "file": "syntaxerror2.py", "startColumn": 0, "endColumn": 0, "startLine": 5, "endLine": 5 }, - "markdownMessage": "A parse error occurred while processing `/repo_dir/syntaxerror2.py`, and as a result this file could not be analyzed. Check the syntax of the file using the `python -m py_compile` command and correct any invalid syntax.", + "markdownMessage": "A parse error occurred while processing `syntaxerror2.py`, and as a result this file could not be analyzed. Check the syntax of the file using the `python -m py_compile` command and correct any invalid syntax.", "severity": "warning", "source": { "extractorName": "python", @@ -145,7 +145,7 @@ ] }, "location": { - "file": "/repo_dir/recursion_error.py" + "file": "recursion_error.py" }, "plaintextMessage": "maximum recursion depth exceeded while calling a Python object", "severity": "error", diff --git a/python/extractor/semmle/logging.py b/python/extractor/semmle/logging.py index 0e0b173a4d7..6f31bff4f39 100644 --- a/python/extractor/semmle/logging.py +++ b/python/extractor/semmle/logging.py @@ -359,11 +359,25 @@ def get_stack_trace_lines(): return lines[:i] return lines +def _get_source_root(): + """Get the source root directory for relativizing diagnostic paths.""" + return os.environ.get("LGTM_SRC", os.getcwd()) + +def _relative_path(path): + """Make a path relative to the source root for use in diagnostic locations. + If the path is not under the source root, return it unchanged.""" + source_root = _get_source_root() + relpath = os.path.relpath(path, source_root) + if relpath.startswith(os.pardir): + return path + return relpath + def syntax_error_message(exception, unit): - l = Location(file=unit.path, startLine=exception.lineno, startColumn=exception.offset) + diag_path = _relative_path(unit.path) + l = Location(file=diag_path, startLine=exception.lineno, startColumn=exception.offset) error = (DiagnosticMessage(Source("py/diagnostics/syntax-error", "Could not process some files due to syntax errors"), Severity.WARNING) .with_location(l) - .markdown("A parse error occurred while processing `{}`, and as a result this file could not be analyzed. Check the syntax of the file using the `python -m py_compile` command and correct any invalid syntax.".format(unit.path)) + .markdown("A parse error occurred while processing `{}`, and as a result this file could not be analyzed. Check the syntax of the file using the `python -m py_compile` command and correct any invalid syntax.".format(diag_path)) .attribute("traceback", get_stack_trace_lines()) .attribute("args", exception.args) .status_page() @@ -374,7 +388,7 @@ def syntax_error_message(exception, unit): def recursion_error_message(exception, unit): # if unit is a BuiltinModuleExtractable, there will be no path attribute - l = Location(file=unit.path) if hasattr(unit, "path") else None + l = Location(file=_relative_path(unit.path)) if hasattr(unit, "path") else None return (DiagnosticMessage(Source("py/diagnostics/recursion-error", "Recursion error in Python extractor"), Severity.ERROR) .with_location(l) .text(exception.args[0]) @@ -385,7 +399,7 @@ def recursion_error_message(exception, unit): def internal_error_message(exception, unit): # if unit is a BuiltinModuleExtractable, there will be no path attribute - l = Location(file=unit.path) if hasattr(unit, "path") else None + l = Location(file=_relative_path(unit.path)) if hasattr(unit, "path") else None return (DiagnosticMessage(Source("py/diagnostics/internal-error", "Internal error in Python extractor"), Severity.ERROR) .with_location(l) .text("Internal error") From ee13ea0f6b5706e4d73f9c7737b281634f24f32b Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 13 May 2026 11:35:02 +0200 Subject: [PATCH 30/36] Harden `_relative_path` for Windows and mixed-form inputs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- python/extractor/semmle/logging.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/python/extractor/semmle/logging.py b/python/extractor/semmle/logging.py index 6f31bff4f39..31805040bf6 100644 --- a/python/extractor/semmle/logging.py +++ b/python/extractor/semmle/logging.py @@ -366,11 +366,16 @@ def _get_source_root(): def _relative_path(path): """Make a path relative to the source root for use in diagnostic locations. If the path is not under the source root, return it unchanged.""" - source_root = _get_source_root() - relpath = os.path.relpath(path, source_root) + source_root = os.path.abspath(_get_source_root()) + abs_path = os.path.abspath(path) + try: + relpath = os.path.relpath(abs_path, source_root) + except ValueError: + # On Windows, relpath raises ValueError for paths on different drives + return path if relpath.startswith(os.pardir): return path - return relpath + return relpath.replace(os.sep, "/") def syntax_error_message(exception, unit): diag_path = _relative_path(unit.path) From 59dbd68a5e49de10d04ac040d50f3145f639d751 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 14 May 2026 14:46:05 +0100 Subject: [PATCH 31/36] Add change notes. --- javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md | 4 ++++ python/ql/lib/change-notes/2026-05-14-sensitive-data.md | 4 ++++ rust/ql/lib/change-notes/2026-05-14-sensitive-data.md | 4 ++++ swift/ql/lib/change-notes/2026-05-14-sensitive-data.md | 4 ++++ 4 files changed, 16 insertions(+) create mode 100644 javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md create mode 100644 python/ql/lib/change-notes/2026-05-14-sensitive-data.md create mode 100644 rust/ql/lib/change-notes/2026-05-14-sensitive-data.md create mode 100644 swift/ql/lib/change-notes/2026-05-14-sensitive-data.md diff --git a/javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md b/javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md new file mode 100644 index 00000000000..341f7babd70 --- /dev/null +++ b/javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `js/clear-text-logging`) may find more correct results and less false positive results after these changes. diff --git a/python/ql/lib/change-notes/2026-05-14-sensitive-data.md b/python/ql/lib/change-notes/2026-05-14-sensitive-data.md new file mode 100644 index 00000000000..d40c7cbba88 --- /dev/null +++ b/python/ql/lib/change-notes/2026-05-14-sensitive-data.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and less false positive results after these changes. diff --git a/rust/ql/lib/change-notes/2026-05-14-sensitive-data.md b/rust/ql/lib/change-notes/2026-05-14-sensitive-data.md new file mode 100644 index 00000000000..478cfea8cbf --- /dev/null +++ b/rust/ql/lib/change-notes/2026-05-14-sensitive-data.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `rust/cleartext-logging`) may find more correct results and less false positive results after these changes. diff --git a/swift/ql/lib/change-notes/2026-05-14-sensitive-data.md b/swift/ql/lib/change-notes/2026-05-14-sensitive-data.md new file mode 100644 index 00000000000..64f6ff3ce76 --- /dev/null +++ b/swift/ql/lib/change-notes/2026-05-14-sensitive-data.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `swift/cleartext-logging`) may find more correct results and less false positive results after these changes. From a4b2c0f6fd22d72516a20bd3ec137e1a461df8d5 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Fri, 15 May 2026 09:24:29 +0100 Subject: [PATCH 32/36] Update change notes (Copilot's suggestions). --- javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md | 2 +- python/ql/lib/change-notes/2026-05-14-sensitive-data.md | 2 +- rust/ql/lib/change-notes/2026-05-14-sensitive-data.md | 2 +- swift/ql/lib/change-notes/2026-05-14-sensitive-data.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md b/javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md index 341f7babd70..f6e6caed325 100644 --- a/javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md +++ b/javascript/ql/lib/change-notes/2026-05-14-sensitive-data.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `js/clear-text-logging`) may find more correct results and less false positive results after these changes. +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `js/clear-text-logging`) may find more correct results and fewer false positive results after these changes. diff --git a/python/ql/lib/change-notes/2026-05-14-sensitive-data.md b/python/ql/lib/change-notes/2026-05-14-sensitive-data.md index d40c7cbba88..49754de35ce 100644 --- a/python/ql/lib/change-notes/2026-05-14-sensitive-data.md +++ b/python/ql/lib/change-notes/2026-05-14-sensitive-data.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and less false positive results after these changes. +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `py/clear-text-logging-sensitive-data`) may find more correct results and less fewer positive results after these changes. diff --git a/rust/ql/lib/change-notes/2026-05-14-sensitive-data.md b/rust/ql/lib/change-notes/2026-05-14-sensitive-data.md index 478cfea8cbf..5aa6febd49b 100644 --- a/rust/ql/lib/change-notes/2026-05-14-sensitive-data.md +++ b/rust/ql/lib/change-notes/2026-05-14-sensitive-data.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `rust/cleartext-logging`) may find more correct results and less false positive results after these changes. +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `rust/cleartext-logging`) may find more correct results and fewer false positive results after these changes. diff --git a/swift/ql/lib/change-notes/2026-05-14-sensitive-data.md b/swift/ql/lib/change-notes/2026-05-14-sensitive-data.md index 64f6ff3ce76..70e96a3469c 100644 --- a/swift/ql/lib/change-notes/2026-05-14-sensitive-data.md +++ b/swift/ql/lib/change-notes/2026-05-14-sensitive-data.md @@ -1,4 +1,4 @@ --- category: minorAnalysis --- -* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `swift/cleartext-logging`) may find more correct results and less false positive results after these changes. +* The sensitive data heuristics used to identify code that handles passwords and private data have been improved. Most of the changes permit more variations of established patterns, thereby finding more sensitive data. Queries that use the sensitive data library (for example `swift/cleartext-logging`) may find more correct results and fewer false positive results after these changes. From 01ff9aa91f3e6fa196ea25fb9c41239bbe081083 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 18 May 2026 14:32:08 +0200 Subject: [PATCH 33/36] Swift: Update to Swift 6.3.2 --- swift/ql/lib/change-notes/2026-05-19-swift-6.3.2.md | 4 ++++ swift/third_party/resources/resource-dir-linux.zip | 4 ++-- swift/third_party/resources/resource-dir-macos.zip | 4 ++-- swift/third_party/resources/swift-prebuilt-linux.tar.zst | 4 ++-- swift/third_party/resources/swift-prebuilt-macos.tar.zst | 4 ++-- 5 files changed, 12 insertions(+), 8 deletions(-) create mode 100644 swift/ql/lib/change-notes/2026-05-19-swift-6.3.2.md diff --git a/swift/ql/lib/change-notes/2026-05-19-swift-6.3.2.md b/swift/ql/lib/change-notes/2026-05-19-swift-6.3.2.md new file mode 100644 index 00000000000..530b7187e7a --- /dev/null +++ b/swift/ql/lib/change-notes/2026-05-19-swift-6.3.2.md @@ -0,0 +1,4 @@ +--- +category: majorAnalysis +--- +* Upgraded to allow analysis of Swift 6.3.2. diff --git a/swift/third_party/resources/resource-dir-linux.zip b/swift/third_party/resources/resource-dir-linux.zip index 8692eb89fd4..da93aefcc70 100644 --- a/swift/third_party/resources/resource-dir-linux.zip +++ b/swift/third_party/resources/resource-dir-linux.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:25718237e4b0d725f62baceb8e9eb6b1090433c3a64c15b54205bbd3b1241a78 -size 408416862 +oid sha256:bd132a4fb44688913eff72f94110e2745048ceda3354ba199d8338750881e0e5 +size 408312701 diff --git a/swift/third_party/resources/resource-dir-macos.zip b/swift/third_party/resources/resource-dir-macos.zip index 51c367e2b13..11ac3ddf0d7 100644 --- a/swift/third_party/resources/resource-dir-macos.zip +++ b/swift/third_party/resources/resource-dir-macos.zip @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97c427650a83bd1d70846ef24965cbe2451c3e9b3bb86530f0cb704936ffa07a -size 548168307 +oid sha256:fd4eaa3a688849279e990da69768da796f6a130ca6e01572d022142ff09e4868 +size 548155566 diff --git a/swift/third_party/resources/swift-prebuilt-linux.tar.zst b/swift/third_party/resources/swift-prebuilt-linux.tar.zst index 769117fefea..2adf23cda68 100644 --- a/swift/third_party/resources/swift-prebuilt-linux.tar.zst +++ b/swift/third_party/resources/swift-prebuilt-linux.tar.zst @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b313be2bee2c0afbedbe710435b7e0836e1a06f6a8b57d300c9843ebd1f469e3 -size 143494508 +oid sha256:e00f464ad0b793c8e14df844aecbeec5cdd587e8f34a85915593a470dba1beda +size 143508114 diff --git a/swift/third_party/resources/swift-prebuilt-macos.tar.zst b/swift/third_party/resources/swift-prebuilt-macos.tar.zst index a48c2ce0466..f63c93f1caa 100644 --- a/swift/third_party/resources/swift-prebuilt-macos.tar.zst +++ b/swift/third_party/resources/swift-prebuilt-macos.tar.zst @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4aea62dad0e67b8bb6ac5536a3fff1730f48a15f516b5b6d48b6c42f16508687 -size 125103802 +oid sha256:212229f7f0545aab03e3034f55d13a665bc568633a5defc72a662c83a06e90cc +size 125133134 From 3119ef6c1ad812def98f5c5d6935e96942b186e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jack=20N=C3=B8rskov=20J=C3=B8rgensen?= Date: Tue, 5 May 2026 14:46:33 +0200 Subject: [PATCH 34/36] Add MaDs for Apache Avro --- .../org.apache.avro.file.model.yml | 29 +++++++++++++++++++ .../llmgenerator/org.apache.avro.model.yml | 29 +++++++++++++++++++ .../org.apache.avro.util.model.yml | 8 +++++ 3 files changed, 66 insertions(+) create mode 100644 java/ql/lib/ext/generated/llmgenerator/org.apache.avro.file.model.yml create mode 100644 java/ql/lib/ext/generated/llmgenerator/org.apache.avro.model.yml create mode 100644 java/ql/lib/ext/generated/llmgenerator/org.apache.avro.util.model.yml diff --git a/java/ql/lib/ext/generated/llmgenerator/org.apache.avro.file.model.yml b/java/ql/lib/ext/generated/llmgenerator/org.apache.avro.file.model.yml new file mode 100644 index 00000000000..185d396fd72 --- /dev/null +++ b/java/ql/lib/ext/generated/llmgenerator/org.apache.avro.file.model.yml @@ -0,0 +1,29 @@ +# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT. +# Generated from https://github.com/apache/avro.git#68da8fb99da5c482f17853e01e79f714e3717b42 by codeql-mads-via-llm +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.apache.avro.file", "DataFileReader", True, "openReader", "(File,DatumReader)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro.file", "DataFileWriter", True, "appendTo", "(File)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro.file", "DataFileWriter", True, "create", "(Schema,File)", "", "Argument[1]", "path-injection", "ai-generated"] + - ["org.apache.avro.file", "SeekableFileInput", True, "SeekableFileInput", "(File)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro.file", "SyncableFileOutputStream", True, "SyncableFileOutputStream", "(File)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro.file", "SyncableFileOutputStream", True, "SyncableFileOutputStream", "(File,boolean)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro.file", "SyncableFileOutputStream", True, "SyncableFileOutputStream", "(String)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro.file", "SyncableFileOutputStream", True, "SyncableFileOutputStream", "(String,boolean)", "", "Argument[0]", "path-injection", "ai-generated"] + - addsTo: + pack: codeql/java-all + extensible: sourceModel + data: + - ["org.apache.avro.file", "DataFileReader12", True, "getMeta", "(String)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro.file", "DataFileReader12", True, "getMetaString", "(String)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro.file", "DataFileReader12", True, "next", "()", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro.file", "DataFileReader12", True, "next", "(Object)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro.file", "DataFileStream", True, "getMeta", "(String)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro.file", "DataFileStream", True, "getMetaString", "(String)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro.file", "DataFileStream", True, "next", "()", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro.file", "DataFileStream", True, "next", "(Object)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro.file", "DataFileStream", True, "nextBlock", "()", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro.file", "FileReader", True, "next", "(Object)", "", "ReturnValue", "file", "ai-generated"] diff --git a/java/ql/lib/ext/generated/llmgenerator/org.apache.avro.model.yml b/java/ql/lib/ext/generated/llmgenerator/org.apache.avro.model.yml new file mode 100644 index 00000000000..e6b5048429c --- /dev/null +++ b/java/ql/lib/ext/generated/llmgenerator/org.apache.avro.model.yml @@ -0,0 +1,29 @@ +# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT. +# Generated from https://github.com/apache/avro.git#68da8fb99da5c482f17853e01e79f714e3717b42 by codeql-mads-via-llm +extensions: + - addsTo: + pack: codeql/java-all + extensible: sinkModel + data: + - ["org.apache.avro", "Protocol", True, "parse", "(File)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro", "Schema", True, "parse", "(File)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro", "Schema$Parser", True, "parse", "(File)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(File)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(File,Charset)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(Path)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(Path,Charset)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(URI,Charset)", "", "Argument[0]", "path-injection", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(URI,Charset)", "", "Argument[0]", "request-forgery", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parseSingle", "(Path)", "", "Argument[0]", "path-injection", "ai-generated"] + - addsTo: + pack: codeql/java-all + extensible: sourceModel + data: + - ["org.apache.avro", "Protocol", True, "parse", "(File)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro", "Schema", True, "parse", "(File)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(File)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(File,Charset)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(Path)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(Path,Charset)", "", "ReturnValue", "file", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parse", "(URI,Charset)", "", "ReturnValue", "remote", "ai-generated"] + - ["org.apache.avro", "SchemaParser", True, "parseSingle", "(Path)", "", "ReturnValue", "file", "ai-generated"] diff --git a/java/ql/lib/ext/generated/llmgenerator/org.apache.avro.util.model.yml b/java/ql/lib/ext/generated/llmgenerator/org.apache.avro.util.model.yml new file mode 100644 index 00000000000..31ca686c9f9 --- /dev/null +++ b/java/ql/lib/ext/generated/llmgenerator/org.apache.avro.util.model.yml @@ -0,0 +1,8 @@ +# THIS FILE IS AN AUTO-GENERATED MODELS AS DATA FILE. DO NOT EDIT. +# Generated from https://github.com/apache/avro.git#68da8fb99da5c482f17853e01e79f714e3717b42 by codeql-mads-via-llm +extensions: + - addsTo: + pack: codeql/java-all + extensible: sourceModel + data: + - ["org.apache.avro.util", "RandomData", True, "main", "(String[])", "", "Argument[0]", "commandargs", "ai-generated"] From 7a1a90b5a4ae891c3c417f2051b3c3e6548ef882 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Tue, 19 May 2026 13:23:22 +0200 Subject: [PATCH 35/36] C#: Address review comment. --- csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll index f1df963d72b..909ba3b9d42 100644 --- a/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/lib/semmle/code/csharp/dispatch/Dispatch.qll @@ -116,7 +116,7 @@ private module Internal { not oc.isLateBound() and not oc instanceof InstanceOperatorCall } or - TDispatchInstanceOperatorCall(InstanceOperatorCall caoc) or + TDispatchInstanceOperatorCall(InstanceOperatorCall ioc) or TDispatchReflectionCall(MethodCall mc, string name, Expr object, Expr qualifier, int args) { isReflectionCall(mc, name, object, qualifier, args) } or From aa136a328297c60e9a5da3f0043b7bd84ecf4870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jack=20N=C3=B8rskov=20J=C3=B8rgensen?= Date: Tue, 19 May 2026 16:09:05 +0200 Subject: [PATCH 36/36] Add change note entry --- java/ql/lib/change-notes/2026-05-19-avro-mads.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 java/ql/lib/change-notes/2026-05-19-avro-mads.md diff --git a/java/ql/lib/change-notes/2026-05-19-avro-mads.md b/java/ql/lib/change-notes/2026-05-19-avro-mads.md new file mode 100644 index 00000000000..43368b098b1 --- /dev/null +++ b/java/ql/lib/change-notes/2026-05-19-avro-mads.md @@ -0,0 +1,4 @@ +--- +category: minorAnalysis +--- +* Added LLM-generated source and sink models for `org.apache.avro`.