Skip to content

Commit f9fc79b

Browse files
authored
Merge pull request github#13930 from geoffw0/uitextinput
Swift: Flow sources for UITextInput
2 parents f377d25 + e828d8d commit f9fc79b

File tree

4 files changed

+69
-8
lines changed

4 files changed

+69
-8
lines changed

docs/codeql/reusables/supported-frameworks.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,4 @@ and the CodeQL library pack ``codeql/swift-all`` (`changelog <https://github.com
310310
`SQLite3 <https://sqlite.org/index.html>`__, Database
311311
`SQLite.swift <https://github.com/stephencelis/SQLite.swift>`__, Database
312312
`WebKit <https://developer.apple.com/documentation/webkit>`__, User interface library
313+
`UIKit <https://developer.apple.com/documentation/uikit>`__, User interface library
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added local flow sources for `UITextInput` and related classes.
Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
/**
2-
* Provides models for the `UITextField` Swift class.
2+
* Provides models for the `UITextField` and related Swift class.
33
*/
44

55
import swift
66
private import codeql.swift.dataflow.ExternalFlow
77

88
/**
9-
* A model for `UITextField` members that are flow sources.
9+
* A model for `UITextField`, `UITextInput` and related class members that are flow sources.
1010
*/
1111
private class UITextFieldSource extends SourceModelCsv {
1212
override predicate row(string row) {
13-
row = [";UITextField;true;text;;;;local", ";UITextField;true;attributedText;;;;local"]
13+
row =
14+
[
15+
";UITextField;true;text;;;;local", ";UITextField;true;attributedText;;;;local",
16+
";UITextFieldDelegate;true;textField(_:shouldChangeCharactersIn:replacementString:);;;Parameter[2];local",
17+
";UITextViewDelegate;true;textView(_:shouldChangeTextIn:replacementText:);;;Parameter[2];local",
18+
";UITextInput;true;text(in:);;;ReturnValue;local",
19+
";UITextInput;true;shouldChangeText(in:replacementText:);;;Parameter[1];local",
20+
]
1421
}
1522
}
Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,82 @@
11
// --- stubs ---
22

33
class NSObject { }
4-
class NSAttributedString: NSObject {}
5-
class UIResponder: NSObject {}
6-
class UIView: UIResponder {}
7-
class UIControl: UIView {}
4+
5+
struct _NSRange { }
6+
7+
typealias NSRange = _NSRange
8+
9+
class NSAttributedString: NSObject { }
10+
11+
class UIResponder: NSObject { }
12+
13+
class UIView: UIResponder { }
14+
15+
class UIControl: UIView { }
16+
17+
class UITextRange : NSObject {
18+
}
19+
20+
protocol UITextInput {
21+
func text(in range: UITextRange) -> String?
22+
23+
func shouldChangeText(in range: UITextRange, replacementText text: String) -> Bool
24+
}
25+
826
class UITextField: UIControl {
927
var text: String? {
1028
get { nil }
1129
set { }
1230
}
31+
1332
var attributedText: NSAttributedString? {
1433
get { nil }
1534
set { }
1635
}
36+
1737
var placeholder: String? {
1838
get { nil }
1939
set { }
2040
}
2141
}
42+
2243
class UISearchTextField : UITextField {
2344
}
2445

46+
protocol UITextFieldDelegate {
47+
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
48+
}
49+
2550
// --- tests ---
2651

27-
func testUITextField(textField: UITextField, searchTextField: UISearchTextField) {
52+
func sink(arg: Any) { }
53+
54+
class MyTextInput : UITextInput {
55+
func text(in range: UITextRange) -> String? { return nil }
56+
func harmless(in range: UITextRange) -> String? { return nil }
57+
58+
func shouldChangeText(in range: UITextRange, replacementText text: String) -> Bool { // $ source=local
59+
sink(arg: text) // $ tainted
60+
61+
return true
62+
}
63+
}
64+
65+
class MyUITextFieldDelegate : UITextFieldDelegate {
66+
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // $ source=local
67+
sink(arg: string) // $ tainted
68+
69+
return true
70+
}
71+
}
72+
73+
func test(textField: UITextField, searchTextField: UISearchTextField, myTextInput: MyTextInput, range: UITextRange) {
2874
_ = textField.text // $ source=local
2975
_ = textField.attributedText // $ source=local
3076
_ = textField.placeholder // GOOD (not input)
3177
_ = textField.text?.uppercased() // $ source=local
3278
_ = searchTextField.text // $ source=local
79+
80+
_ = myTextInput.text(in: range)! // $ source=local
81+
_ = myTextInput.harmless(in: range)! // GOOD (not input)
3382
}

0 commit comments

Comments
 (0)