@@ -13,31 +13,52 @@ use crate::Mutability;
13
13
#[ derive( Debug , PartialEq , Clone ) ]
14
14
pub struct Cache < ' a > {
15
15
config : & ' a Config ,
16
- mainthreadonly_classes : BTreeSet < ItemIdentifier > ,
16
+ mainthreadonly_items : BTreeSet < ItemIdentifier > ,
17
17
}
18
18
19
19
impl < ' a > Cache < ' a > {
20
20
pub fn new ( output : & Output , config : & ' a Config ) -> Self {
21
- let mut mainthreadonly_classes = BTreeSet :: new ( ) ;
21
+ let mut mainthreadonly_items = BTreeSet :: new ( ) ;
22
22
23
23
for library in output. libraries . values ( ) {
24
24
for file in library. files . values ( ) {
25
25
for stmt in file. stmts . iter ( ) {
26
- if let Stmt :: ClassDecl {
27
- id,
28
- mutability : Mutability :: MainThreadOnly ,
29
- ..
30
- } = stmt
31
- {
32
- mainthreadonly_classes. insert ( id. clone ( ) ) ;
26
+ match stmt {
27
+ Stmt :: ClassDecl {
28
+ id,
29
+ mutability : Mutability :: MainThreadOnly ,
30
+ ..
31
+ } => {
32
+ mainthreadonly_items. insert ( id. clone ( ) ) ;
33
+ }
34
+ Stmt :: ProtocolDecl {
35
+ id,
36
+ required_mainthreadonly : true ,
37
+ ..
38
+ } => {
39
+ mainthreadonly_items. insert ( id. clone ( ) ) ;
40
+ }
41
+ Stmt :: ProtocolDecl {
42
+ id,
43
+ required_mainthreadonly : false ,
44
+ protocols,
45
+ ..
46
+ } => {
47
+ for protocol in protocols {
48
+ if mainthreadonly_items. contains ( protocol) {
49
+ let _ = mainthreadonly_items. insert ( id. clone ( ) ) ;
50
+ }
51
+ }
52
+ }
53
+ _ => { }
33
54
}
34
55
}
35
56
}
36
57
}
37
58
38
59
Self {
39
60
config,
40
- mainthreadonly_classes ,
61
+ mainthreadonly_items ,
41
62
}
42
63
}
43
64
@@ -100,50 +121,51 @@ impl<'a> Cache<'a> {
100
121
for method in methods. iter_mut ( ) {
101
122
let mut result_type_contains_mainthreadonly: bool = false ;
102
123
method. result_type . visit_required_types ( & mut |id| {
103
- if self . mainthreadonly_classes . contains ( id) {
124
+ if self . mainthreadonly_items . contains ( id) {
104
125
result_type_contains_mainthreadonly = true ;
105
126
}
106
127
} ) ;
107
128
108
- match ( method. is_class , self . mainthreadonly_classes . contains ( id) ) {
109
- // MainThreadOnly class with static method
110
- ( true , true ) => {
111
- // Assume the method needs main thread
112
- result_type_contains_mainthreadonly = true ;
113
- }
114
- // Class with static method
115
- ( true , false ) => {
116
- // Continue with the normal check
117
- }
118
- // MainThreadOnly class with non-static method
119
- ( false , true ) => {
120
- // Method is already required to run on main
121
- // thread, so no need to add MainThreadMarker
122
- continue ;
123
- }
124
- // Class with non-static method
125
- ( false , false ) => {
126
- // Continue with the normal check
127
- }
129
+ let mut any_argument_contains_mainthreadonly: bool = false ;
130
+ for ( _, argument) in method. arguments . iter ( ) {
131
+ // Important: We only visit the top-level types, to not
132
+ // include optional arguments like `Option<&NSView>` or
133
+ // `&NSArray<NSView>`.
134
+ argument. visit_toplevel_types ( & mut |id| {
135
+ if self . mainthreadonly_items . contains ( id) {
136
+ any_argument_contains_mainthreadonly = true ;
137
+ }
138
+ } ) ;
128
139
}
129
140
130
- if result_type_contains_mainthreadonly {
131
- let mut any_argument_contains_mainthreadonly: bool = false ;
132
- for ( _, argument) in method. arguments . iter ( ) {
133
- // Important: We only visit the top-level types, to not
134
- // include e.g. `Option<&NSView>` or `&NSArray<NSView>`.
135
- argument. visit_toplevel_types ( & mut |id| {
136
- if self . mainthreadonly_classes . contains ( id) {
137
- any_argument_contains_mainthreadonly = true ;
138
- }
139
- } ) ;
141
+ if self . mainthreadonly_items . contains ( id) {
142
+ if method. is_class {
143
+ // Assume the method needs main thread if it's
144
+ // declared on a main thread only class.
145
+ result_type_contains_mainthreadonly = true ;
146
+ } else {
147
+ // Method takes `&self` or `&mut self`, or is
148
+ // an initialization method, all of which
149
+ // already require the main thread.
150
+ //
151
+ // Note: Initialization methods can be passed
152
+ // `None`, but in that case the return will
153
+ // always be NULL.
154
+ any_argument_contains_mainthreadonly = true ;
140
155
}
156
+ }
141
157
142
- // Apply main thread only, unless a (required)
143
- // argument was main thread only.
144
- if !any_argument_contains_mainthreadonly {
145
- method. mainthreadonly = true ;
146
- }
158
+ if any_argument_contains_mainthreadonly {
159
+ // MainThreadMarker can be retrieved from
160
+ // `MainThreadMarker::from` inside these methods,
161
+ // and hence passing it is redundant.
162
+ method. mainthreadonly = false ;
163
+ } else if result_type_contains_mainthreadonly {
164
+ method. mainthreadonly = true ;
165
+ } else {
166
+ // If neither, then we respect any annotation
167
+ // the method may have had before
168
+ // method.mainthreadonly = method.mainthreadonly;
147
169
}
148
170
}
149
171
}
0 commit comments