1use std::collections::HashMap;
2
3use log::{error, info};
4
5use crate::{
6 analysis::types::IsIncomplete,
7 config::{
8 gobjects::{GObject, GStatus},
9 matchable::Matchable,
10 Config, WorkMode,
11 },
12 library::*,
13 nameutil,
14 parser::is_empty_c_type,
15 traits::MaybeRefAs,
16};
17
18impl Namespace {
19 fn unresolved(&self) -> Vec<&str> {
20 self.index
21 .iter()
22 .filter_map(|(name, &id)| {
23 if self.types[id as usize].is_none() {
24 Some(name.as_str())
25 } else {
26 None
27 }
28 })
29 .collect()
30 }
31}
32
33type DetectedCTypes = HashMap<TypeId, String>;
34
35impl Library {
36 pub fn postprocessing(&mut self, config: &Config) {
37 self.fix_gtype();
38 self.check_resolved();
39 self.fill_empty_signals_c_types();
40 self.resolve_class_structs();
41 self.correlate_class_structs();
42 self.fix_fields();
43 self.make_unrepresentable_types_opaque();
44 self.mark_final_types(config);
45 self.update_error_domain_functions(config);
46 self.mark_ignored_enum_members(config);
47 }
48
49 fn fix_gtype(&mut self) {
50 if let Some(ns_id) = self.find_namespace("GObject") {
51 self.add_type(ns_id, "Type", Type::Basic(Basic::Unsupported));
53 }
54 }
55
56 fn check_resolved(&self) {
57 let list: Vec<_> = self
58 .index
59 .iter()
60 .flat_map(|(name, &id)| {
61 let name = name.clone();
62 self.namespace(id)
63 .unresolved()
64 .into_iter()
65 .map(move |s| format!("{name}.{s}"))
66 })
67 .collect();
68
69 assert!(list.is_empty(), "Incomplete library, unresolved: {list:?}");
70 }
71
72 fn fill_empty_signals_c_types(&mut self) {
73 fn update_empty_signals_c_types(signals: &mut [Signal], c_types: &DetectedCTypes) {
74 for signal in signals {
75 update_empty_signal_c_types(signal, c_types);
76 }
77 }
78
79 fn update_empty_signal_c_types(signal: &mut Signal, c_types: &DetectedCTypes) {
80 for par in &mut signal.parameters {
81 update_empty_c_type(&mut par.c_type, par.typ, c_types);
82 }
83 update_empty_c_type(&mut signal.ret.c_type, signal.ret.typ, c_types);
84 }
85
86 fn update_empty_c_type(c_type: &mut String, tid: TypeId, c_types: &DetectedCTypes) {
87 if !is_empty_c_type(c_type) {
88 return;
89 }
90 if let Some(s) = c_types.get(&tid) {
91 *c_type = s.clone();
92 }
93 }
94
95 let mut tids = Vec::new();
96 let mut c_types = DetectedCTypes::new();
97 for (ns_id, ns) in self.namespaces.iter().enumerate() {
98 for (id, type_) in ns.types.iter().enumerate() {
99 let type_ = type_.as_ref().unwrap(); let tid = TypeId {
101 ns_id: ns_id as u16,
102 id: id as u32,
103 };
104 match type_ {
105 Type::Class(klass) => {
106 if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) {
107 tids.push(tid);
108 }
109 }
110 Type::Interface(iface) => {
111 if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) {
112 tids.push(tid);
113 }
114 }
115 _ => (),
116 }
117 }
118 }
119
120 for tid in tids {
121 match self.type_mut(tid) {
122 Type::Class(klass) => update_empty_signals_c_types(&mut klass.signals, &c_types),
123 Type::Interface(iface) => {
124 update_empty_signals_c_types(&mut iface.signals, &c_types);
125 }
126 _ => (),
127 }
128 }
129 }
130
131 fn detect_empty_signals_c_types(
132 &self,
133 signals: &[Signal],
134 c_types: &mut DetectedCTypes,
135 ) -> bool {
136 let mut detected = false;
137 for signal in signals {
138 if self.detect_empty_signal_c_types(signal, c_types) {
139 detected = true;
140 }
141 }
142 detected
143 }
144
145 fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
146 let mut detected = false;
147 for par in &signal.parameters {
148 if self.detect_empty_c_type(&par.c_type, par.typ, c_types) {
149 detected = true;
150 }
151 }
152 if self.detect_empty_c_type(&signal.ret.c_type, signal.ret.typ, c_types) {
153 detected = true;
154 }
155 detected
156 }
157
158 fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
159 if !is_empty_c_type(c_type) {
160 return false;
161 }
162 if let std::collections::hash_map::Entry::Vacant(entry) = c_types.entry(tid) {
163 if let Some(detected_c_type) = self.c_type_by_type_id(tid) {
164 entry.insert(detected_c_type);
165 }
166 }
167 true
168 }
169
170 fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
171 let type_ = self.type_(tid);
172 type_.get_glib_name().map(|glib_name| {
173 if self.is_referenced_type(type_) {
174 format!("{glib_name}*")
175 } else {
176 glib_name.to_string()
177 }
178 })
179 }
180
181 fn is_referenced_type(&self, type_: &Type) -> bool {
182 use crate::library::Type::*;
183 match type_ {
184 Alias(alias) => self.is_referenced_type(self.type_(alias.typ)),
185 Record(..) | Union(..) | Class(..) | Interface(..) => true,
186 _ => false,
187 }
188 }
189
190 fn resolve_class_structs(&mut self) {
191 let mut structs_and_types = Vec::new();
193
194 for (ns_id, ns) in self.namespaces.iter().enumerate() {
195 for type_ in &ns.types {
196 let type_ = type_.as_ref().unwrap(); if let Type::Record(record) = type_ {
199 if let Some(ref struct_for) = record.gtype_struct_for {
200 if let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for) {
201 structs_and_types.push((record.c_type.clone(), struct_for_tid));
202 }
203 }
204 }
205 }
206 }
207
208 for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
209 match self.type_mut(struct_for_tid) {
210 Type::Class(klass) => {
211 klass.c_class_type = Some(gtype_struct_c_type);
212 }
213
214 Type::Interface(iface) => {
215 iface.c_class_type = Some(gtype_struct_c_type);
216 }
217
218 x => unreachable!(
219 "Something other than a class or interface has a class struct: {:?}",
220 x
221 ),
222 }
223 }
224 }
225
226 fn correlate_class_structs(&self) {
227 for (ns_id, ns) in self.namespaces.iter().enumerate() {
228 for type_ in &ns.types {
229 let type_ = type_.as_ref().unwrap(); let name;
231 let type_struct;
232 let c_class_type;
233
234 match type_ {
235 Type::Class(klass) => {
236 name = &klass.name;
237 type_struct = &klass.type_struct;
238 c_class_type = &klass.c_class_type;
239 }
240
241 Type::Interface(iface) => {
242 name = &iface.name;
243 type_struct = &iface.type_struct;
244 c_class_type = &iface.c_class_type;
245 }
246
247 _ => {
248 continue;
249 }
250 }
251
252 if let Some(type_struct) = type_struct {
253 let type_struct_tid = self.find_type(ns_id as u16, type_struct);
254 assert!(
255 type_struct_tid.is_some(),
256 "\"{name}\" has glib:type-struct=\"{type_struct}\" but there is no such record"
257 );
258
259 let type_struct_type = self.type_(type_struct_tid.unwrap());
260
261 if let Type::Record(r) = type_struct_type {
262 if r.gtype_struct_for.as_ref() != Some(name) {
263 if let Some(ref gtype_struct_for) = r.gtype_struct_for {
264 panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
265 name,
266 type_struct,
267 r.name,
268 gtype_struct_for);
269 } else {
270 panic!("\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
271 name,
272 type_struct,
273 r.name);
274 }
275 }
276 } else {
277 panic!(
278 "Element with name=\"{type_struct}\" should be a record but it isn't"
279 );
280 }
281 } else if let Some(c) = c_class_type {
282 panic!("\"{name}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{c}\"");
283 }
284 }
288 }
289 }
290
291 fn fix_fields(&mut self) {
292 enum Action {
293 SetCType(String),
294 SetName(String),
295 }
296 let mut actions: Vec<(TypeId, usize, Action)> = Vec::new();
297 for (ns_id, ns) in self.namespaces.iter().enumerate() {
298 for (id, type_) in ns.types.iter().enumerate() {
299 let type_ = type_.as_ref().unwrap(); let tid = TypeId {
301 ns_id: ns_id as u16,
302 id: id as u32,
303 };
304 match type_ {
305 Type::Class(Class { name, fields, .. })
306 | Type::Record(Record { name, fields, .. })
307 | Type::Union(Union { name, fields, .. }) => {
308 for (fid, field) in fields.iter().enumerate() {
309 if nameutil::needs_mangling(&field.name) {
310 let new_name = nameutil::mangle_keywords(&*field.name).into_owned();
311 actions.push((tid, fid, Action::SetName(new_name)));
312 }
313 if field.c_type.is_some() {
314 continue;
315 }
316 let field_type = self.type_(field.typ);
317 if field_type.maybe_ref_as::<Function>().is_some() {
318 continue;
320 }
321 if let Some(c_type) = field_type.get_glib_name() {
322 actions.push((tid, fid, Action::SetCType(c_type.to_owned())));
323 continue;
324 }
325 if let Type::Basic(Basic::Pointer) = field_type {
326 actions.push((tid, fid, Action::SetCType("void*".to_owned())));
328 continue;
329 }
330 if let Type::FixedArray(..) = field_type {
331 let array_c_type = "fixed_array".to_owned();
335 actions.push((tid, fid, Action::SetCType(array_c_type)));
336 continue;
337 }
338 error!("Field `{}::{}` is missing c:type", name, &field.name);
339 }
340 }
341 _ => {}
342 }
343 }
344 }
345 let ignore_missing_ctype = ["padding", "reserved", "_padding", "_reserved"];
346 for (tid, fid, action) in actions {
347 match self.type_mut(tid) {
348 Type::Class(Class { name, fields, .. })
349 | Type::Record(Record { name, fields, .. })
350 | Type::Union(Union { name, fields, .. }) => match action {
351 Action::SetCType(c_type) => {
352 if !ignore_missing_ctype.contains(&fields[fid].name.as_str()) {
355 warn_main!(
356 tid,
357 "Field `{}::{}` missing c:type assumed to be `{}`",
358 name,
359 &fields[fid].name,
360 c_type
361 );
362 }
363 fields[fid].c_type = Some(c_type);
364 }
365 Action::SetName(name) => fields[fid].name = name,
366 },
367 _ => unreachable!("Expected class, record or union"),
368 }
369 }
370 }
371
372 fn make_unrepresentable_types_opaque(&mut self) {
373 let mut unrepresentable: Vec<TypeId> = Vec::new();
382 for (ns_id, ns) in self.namespaces.iter().enumerate() {
383 for (id, type_) in ns.types.iter().enumerate() {
384 let type_ = type_.as_ref().unwrap();
385 let tid = TypeId {
386 ns_id: ns_id as u16,
387 id: id as u32,
388 };
389 match type_ {
390 Type::Union(Union { fields, .. }) if fields.as_slice().is_incomplete(self) => {
391 unrepresentable.push(tid);
392 }
393 _ => {}
394 }
395 }
396 }
397 for tid in unrepresentable {
398 match self.type_mut(tid) {
399 Type::Union(Union { name, fields, .. }) => {
400 info!("Type `{}` is not representable.", name);
401 fields.clear();
402 }
403 _ => unreachable!("Expected a union"),
404 }
405 }
406 }
407
408 fn has_subtypes(&self, parent_tid: TypeId) -> bool {
409 for (tid, _) in self.types() {
410 if let Type::Class(class) = self.type_(tid) {
411 if class.parent == Some(parent_tid) {
412 return true;
413 }
414 }
415 }
416
417 false
418 }
419
420 fn mark_final_types(&mut self, config: &Config) {
421 let mut overridden_final_types: Vec<(TypeId, bool)> = Vec::new();
431
432 for (ns_id, ns) in self.namespaces.iter().enumerate() {
433 for (id, type_) in ns.types.iter().enumerate() {
434 let type_ = type_.as_ref().unwrap(); if let Type::Class(klass) = type_ {
437 let tid = TypeId {
438 ns_id: ns_id as u16,
439 id: id as u32,
440 };
441
442 let full_name = tid.full_name(self);
443 let obj = config.objects.get(&*full_name);
444
445 if let Some(GObject {
446 final_type: Some(final_type),
447 ..
448 }) = obj
449 {
450 overridden_final_types.push((tid, *final_type));
453 } else if klass.final_type {
454 continue;
455 } else if klass.type_struct.is_none() {
456 let is_final = !self.has_subtypes(tid);
457 if is_final {
458 overridden_final_types.push((tid, true));
459 }
460 } else {
461 let has_subtypes = self.has_subtypes(tid);
462 let instance_struct_known = !klass.fields.is_empty();
463
464 let class_struct_known = if let Some(class_record_tid) =
465 self.find_type(ns_id as u16, klass.type_struct.as_ref().unwrap())
466 {
467 if let Type::Record(record) = self.type_(class_record_tid) {
468 !record.disguised && !record.pointer
469 } else {
470 unreachable!("Type {} with non-record class", full_name);
471 }
472 } else {
473 unreachable!("Can't find class for {}", full_name);
474 };
475
476 let is_final =
477 !has_subtypes && (!instance_struct_known || !class_struct_known);
478 if is_final {
479 overridden_final_types.push((tid, true));
480 }
481 };
482 }
483 }
484 }
485
486 for (tid, new_is_final) in overridden_final_types {
487 if let Type::Class(Class { final_type, .. }) = self.type_mut(tid) {
488 *final_type = new_is_final;
489 } else {
490 unreachable!();
491 }
492 }
493 }
494
495 fn update_error_domain_functions(&mut self, config: &Config) {
496 let mut error_domains = vec![];
498 for (ns_id, ns) in self.namespaces.iter().enumerate() {
499 'next_enum: for (id, type_) in ns.types.iter().enumerate() {
500 let type_ = type_.as_ref().unwrap(); let enum_tid = TypeId {
502 ns_id: ns_id as u16,
503 id: id as u32,
504 };
505
506 if let Type::Enumeration(enum_) = type_ {
507 if let Some(ErrorDomain::Quark(ref domain)) = enum_.error_domain {
508 let domain = domain.replace('-', "_");
509
510 let mut function_candidates = vec![domain.clone()];
511 if !domain.ends_with("_quark") {
512 function_candidates.push(format!("{domain}_quark"));
513 }
514 if !domain.ends_with("_error_quark") {
515 if domain.ends_with("_quark") {
516 function_candidates
517 .push(format!("{}_error_quark", &domain[..(domain.len() - 6)]));
518 } else {
519 function_candidates.push(format!("{domain}_error_quark"));
520 }
521 }
522 if let Some(domain) = domain.strip_suffix("_error_quark") {
523 function_candidates.push(domain.to_owned());
524 }
525 if let Some(domain) = domain.strip_suffix("_quark") {
526 function_candidates.push(domain.to_owned());
527 }
528
529 if let Some(func) = ns.functions.iter().find(|f| {
530 function_candidates
531 .iter()
532 .any(|c| f.c_identifier.as_ref() == Some(c))
533 }) {
534 error_domains.push((
535 ns_id,
536 enum_tid,
537 None,
538 func.c_identifier.as_ref().unwrap().clone(),
539 ));
540 continue 'next_enum;
541 }
542
543 for (id, type_) in ns.types.iter().enumerate() {
545 let type_ = type_.as_ref().unwrap(); let domain_tid = TypeId {
547 ns_id: ns_id as u16,
548 id: id as u32,
549 };
550
551 let functions = match type_ {
552 Type::Enumeration(Enumeration { functions, .. })
553 | Type::Class(Class { functions, .. })
554 | Type::Record(Record { functions, .. })
555 | Type::Interface(Interface { functions, .. }) => functions,
556 _ => continue,
557 };
558
559 if let Some(func) = functions.iter().find(|f| {
560 function_candidates
561 .iter()
562 .any(|c| f.c_identifier.as_ref() == Some(c))
563 }) {
564 error_domains.push((
565 ns_id,
566 enum_tid,
567 Some(domain_tid),
568 func.c_identifier.as_ref().unwrap().clone(),
569 ));
570 continue 'next_enum;
571 }
572 }
573 }
574 }
575 }
576 }
577
578 for (ns_id, enum_tid, domain_tid, function_name) in error_domains {
579 if config.work_mode != WorkMode::Sys {
580 if let Some(domain_tid) = domain_tid {
581 match self.type_mut(domain_tid) {
582 Type::Enumeration(Enumeration { functions, .. })
583 | Type::Class(Class { functions, .. })
584 | Type::Record(Record { functions, .. })
585 | Type::Interface(Interface { functions, .. }) => {
586 let pos = functions
587 .iter()
588 .position(|f| f.c_identifier.as_ref() == Some(&function_name))
589 .unwrap();
590 functions.remove(pos);
591 }
592 _ => unreachable!(),
593 }
594 } else {
595 let pos = self.namespaces[ns_id]
596 .functions
597 .iter()
598 .position(|f| f.c_identifier.as_ref() == Some(&function_name))
599 .unwrap();
600 self.namespaces[ns_id].functions.remove(pos);
601 }
602 }
603
604 if let Type::Enumeration(enum_) = self.type_mut(enum_tid) {
605 assert!(enum_.error_domain.is_some());
606 enum_.error_domain = Some(ErrorDomain::Function(function_name));
607 } else {
608 unreachable!();
609 }
610 }
611 }
612
613 fn mark_ignored_enum_members(&mut self, config: &Config) {
614 let mut members_to_change = vec![];
615 for (ns_id, ns) in self.namespaces.iter().enumerate() {
616 for (id, _type_) in ns.types.iter().enumerate() {
617 let type_id = TypeId {
618 ns_id: ns_id as u16,
619 id: id as u32,
620 };
621
622 match self.type_(type_id) {
623 Type::Bitfield(Bitfield { name, members, .. })
624 | Type::Enumeration(Enumeration { name, members, .. }) => {
625 let full_name = format!("{}.{}", ns.name, name);
626 let config = config.objects.get(&full_name);
627 let mut type_members = HashMap::new();
628 for member in members.iter() {
629 let status = config.and_then(|m| {
630 m.members.matched(&member.name).first().map(|m| m.status)
631 });
632 type_members.insert(member.c_identifier.clone(), status);
633 }
634 members_to_change.push((type_id, type_members));
635 }
636 _ => (),
637 };
638 }
639 }
640
641 for (type_id, item_members) in members_to_change {
642 match self.type_mut(type_id) {
643 Type::Bitfield(Bitfield { members, .. })
644 | Type::Enumeration(Enumeration { members, .. }) => {
645 for member in members.iter_mut() {
646 let status = item_members
647 .get(&member.c_identifier)
648 .copied()
649 .flatten()
650 .unwrap_or(GStatus::Generate);
651 member.status = status;
652 }
653 }
654 _ => (),
655 };
656 }
657 }
658}