1use std::collections::HashMap;
2
3use log::{error, info};
4
5use crate::{
6 analysis::types::IsIncomplete,
7 config::{
8 Config, WorkMode,
9 gobjects::{GObject, GStatus},
10 matchable::Matchable,
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 && let Some(detected_c_type) = self.c_type_by_type_id(tid)
164 {
165 entry.insert(detected_c_type);
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 && let Some(ref struct_for) = record.gtype_struct_for
200 && let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for)
201 {
202 structs_and_types.push((record.c_type.clone(), struct_for_tid));
203 }
204 }
205 }
206
207 for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
208 match self.type_mut(struct_for_tid) {
209 Type::Class(klass) => {
210 klass.c_class_type = Some(gtype_struct_c_type);
211 }
212
213 Type::Interface(iface) => {
214 iface.c_class_type = Some(gtype_struct_c_type);
215 }
216
217 x => unreachable!(
218 "Something other than a class or interface has a class struct: {:?}",
219 x
220 ),
221 }
222 }
223 }
224
225 fn correlate_class_structs(&self) {
226 for (ns_id, ns) in self.namespaces.iter().enumerate() {
227 for type_ in &ns.types {
228 let type_ = type_.as_ref().unwrap(); let name;
230 let type_struct;
231 let c_class_type;
232
233 match type_ {
234 Type::Class(klass) => {
235 name = &klass.name;
236 type_struct = &klass.type_struct;
237 c_class_type = &klass.c_class_type;
238 }
239
240 Type::Interface(iface) => {
241 name = &iface.name;
242 type_struct = &iface.type_struct;
243 c_class_type = &iface.c_class_type;
244 }
245
246 _ => {
247 continue;
248 }
249 }
250
251 if let Some(type_struct) = type_struct {
252 let type_struct_tid = self.find_type(ns_id as u16, type_struct);
253 assert!(
254 type_struct_tid.is_some(),
255 "\"{name}\" has glib:type-struct=\"{type_struct}\" but there is no such record"
256 );
257
258 let type_struct_type = self.type_(type_struct_tid.unwrap());
259
260 if let Type::Record(r) = type_struct_type {
261 if r.gtype_struct_for.as_ref() != Some(name) {
262 if let Some(ref gtype_struct_for) = r.gtype_struct_for {
263 panic!(
264 "\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
265 name, type_struct, r.name, gtype_struct_for
266 );
267 } else {
268 panic!(
269 "\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
270 name, type_struct, r.name
271 );
272 }
273 }
274 } else {
275 panic!(
276 "Element with name=\"{type_struct}\" should be a record but it isn't"
277 );
278 }
279 } else if let Some(c) = c_class_type {
280 panic!(
281 "\"{name}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{c}\""
282 );
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 if let Type::CArray(..) = field_type {
339 let array_c_type = "c_array".to_owned();
344 actions.push((tid, fid, Action::SetCType(array_c_type)));
345 continue;
346 }
347 error!("Field `{}::{}` is missing c:type", name, &field.name);
348 }
349 }
350 _ => {}
351 }
352 }
353 }
354 let ignore_missing_ctype = ["padding", "reserved", "_padding", "_reserved"];
355 for (tid, fid, action) in actions {
356 match self.type_mut(tid) {
357 Type::Class(Class { name, fields, .. })
358 | Type::Record(Record { name, fields, .. })
359 | Type::Union(Union { name, fields, .. }) => match action {
360 Action::SetCType(c_type) => {
361 if !ignore_missing_ctype.contains(&fields[fid].name.as_str()) {
364 warn_main!(
365 tid,
366 "Field `{}::{}` missing c:type assumed to be `{}`",
367 name,
368 &fields[fid].name,
369 c_type
370 );
371 }
372 fields[fid].c_type = Some(c_type);
373 }
374 Action::SetName(name) => fields[fid].name = name,
375 },
376 _ => unreachable!("Expected class, record or union"),
377 }
378 }
379 }
380
381 fn make_unrepresentable_types_opaque(&mut self) {
382 let mut unrepresentable: Vec<TypeId> = Vec::new();
391 for (ns_id, ns) in self.namespaces.iter().enumerate() {
392 for (id, type_) in ns.types.iter().enumerate() {
393 let type_ = type_.as_ref().unwrap();
394 let tid = TypeId {
395 ns_id: ns_id as u16,
396 id: id as u32,
397 };
398 match type_ {
399 Type::Union(Union { fields, .. }) if fields.as_slice().is_incomplete(self) => {
400 unrepresentable.push(tid);
401 }
402 _ => {}
403 }
404 }
405 }
406 for tid in unrepresentable {
407 match self.type_mut(tid) {
408 Type::Union(Union { name, fields, .. }) => {
409 info!("Type `{name}` is not representable.");
410 fields.clear();
411 }
412 _ => unreachable!("Expected a union"),
413 }
414 }
415 }
416
417 fn has_subtypes(&self, parent_tid: TypeId) -> bool {
418 for (tid, _) in self.types() {
419 if let Type::Class(class) = self.type_(tid)
420 && class.parent == Some(parent_tid)
421 {
422 return true;
423 }
424 }
425
426 false
427 }
428
429 fn mark_final_types(&mut self, config: &Config) {
430 let mut overridden_final_types: Vec<(TypeId, bool)> = Vec::new();
440
441 for (ns_id, ns) in self.namespaces.iter().enumerate() {
442 for (id, type_) in ns.types.iter().enumerate() {
443 let type_ = type_.as_ref().unwrap(); if let Type::Class(klass) = type_ {
446 let tid = TypeId {
447 ns_id: ns_id as u16,
448 id: id as u32,
449 };
450
451 let full_name = tid.full_name(self);
452 let obj = config.objects.get(&*full_name);
453
454 if let Some(GObject {
455 final_type: Some(final_type),
456 ..
457 }) = obj
458 {
459 overridden_final_types.push((tid, *final_type));
462 } else if klass.final_type {
463 continue;
464 } else if klass.type_struct.is_none() {
465 let is_final = !self.has_subtypes(tid);
466 if is_final {
467 overridden_final_types.push((tid, true));
468 }
469 } else {
470 let has_subtypes = self.has_subtypes(tid);
471 let instance_struct_known = !klass.fields.is_empty();
472
473 let class_struct_known = if let Some(class_record_tid) =
474 self.find_type(ns_id as u16, klass.type_struct.as_ref().unwrap())
475 {
476 if let Type::Record(record) = self.type_(class_record_tid) {
477 !record.disguised && !record.pointer
478 } else {
479 unreachable!("Type {} with non-record class", full_name);
480 }
481 } else {
482 unreachable!("Can't find class for {}", full_name);
483 };
484
485 let is_final =
486 !has_subtypes && (!instance_struct_known || !class_struct_known);
487 if is_final {
488 overridden_final_types.push((tid, true));
489 }
490 };
491 }
492 }
493 }
494
495 for (tid, new_is_final) in overridden_final_types {
496 if let Type::Class(Class { final_type, .. }) = self.type_mut(tid) {
497 *final_type = new_is_final;
498 } else {
499 unreachable!();
500 }
501 }
502 }
503
504 fn update_error_domain_functions(&mut self, config: &Config) {
505 let mut error_domains = vec![];
507 for (ns_id, ns) in self.namespaces.iter().enumerate() {
508 'next_enum: for (id, type_) in ns.types.iter().enumerate() {
509 let type_ = type_.as_ref().unwrap(); let enum_tid = TypeId {
511 ns_id: ns_id as u16,
512 id: id as u32,
513 };
514
515 if let Type::Enumeration(enum_) = type_
516 && let Some(ErrorDomain::Quark(ref domain)) = enum_.error_domain
517 {
518 let domain = domain.replace('-', "_");
519
520 let mut function_candidates = vec![domain.clone()];
521 if !domain.ends_with("_quark") {
522 function_candidates.push(format!("{domain}_quark"));
523 }
524 if !domain.ends_with("_error_quark") {
525 if domain.ends_with("_quark") {
526 function_candidates
527 .push(format!("{}_error_quark", &domain[..(domain.len() - 6)]));
528 } else {
529 function_candidates.push(format!("{domain}_error_quark"));
530 }
531 }
532 if let Some(domain) = domain.strip_suffix("_error_quark") {
533 function_candidates.push(domain.to_owned());
534 }
535 if let Some(domain) = domain.strip_suffix("_quark") {
536 function_candidates.push(domain.to_owned());
537 }
538
539 if let Some(func) = ns.functions.iter().find(|f| {
540 function_candidates
541 .iter()
542 .any(|c| f.c_identifier.as_ref() == Some(c))
543 }) {
544 error_domains.push((
545 ns_id,
546 enum_tid,
547 None,
548 func.c_identifier.as_ref().unwrap().clone(),
549 ));
550 continue 'next_enum;
551 }
552
553 for (id, type_) in ns.types.iter().enumerate() {
555 let type_ = type_.as_ref().unwrap(); let domain_tid = TypeId {
557 ns_id: ns_id as u16,
558 id: id as u32,
559 };
560
561 let functions = match type_ {
562 Type::Enumeration(Enumeration { functions, .. })
563 | Type::Class(Class { functions, .. })
564 | Type::Record(Record { functions, .. })
565 | Type::Interface(Interface { functions, .. }) => functions,
566 _ => continue,
567 };
568
569 if let Some(func) = functions.iter().find(|f| {
570 function_candidates
571 .iter()
572 .any(|c| f.c_identifier.as_ref() == Some(c))
573 }) {
574 error_domains.push((
575 ns_id,
576 enum_tid,
577 Some(domain_tid),
578 func.c_identifier.as_ref().unwrap().clone(),
579 ));
580 continue 'next_enum;
581 }
582 }
583 }
584 }
585 }
586
587 for (ns_id, enum_tid, domain_tid, function_name) in error_domains {
588 if config.work_mode != WorkMode::Sys {
589 if let Some(domain_tid) = domain_tid {
590 match self.type_mut(domain_tid) {
591 Type::Enumeration(Enumeration { functions, .. })
592 | Type::Class(Class { functions, .. })
593 | Type::Record(Record { functions, .. })
594 | Type::Interface(Interface { functions, .. }) => {
595 let pos = functions
596 .iter()
597 .position(|f| f.c_identifier.as_ref() == Some(&function_name))
598 .unwrap();
599 functions.remove(pos);
600 }
601 _ => unreachable!(),
602 }
603 } else {
604 let pos = self.namespaces[ns_id]
605 .functions
606 .iter()
607 .position(|f| f.c_identifier.as_ref() == Some(&function_name))
608 .unwrap();
609 self.namespaces[ns_id].functions.remove(pos);
610 }
611 }
612
613 if let Type::Enumeration(enum_) = self.type_mut(enum_tid) {
614 assert!(enum_.error_domain.is_some());
615 enum_.error_domain = Some(ErrorDomain::Function(function_name));
616 } else {
617 unreachable!();
618 }
619 }
620 }
621
622 fn mark_ignored_enum_members(&mut self, config: &Config) {
623 let mut members_to_change = vec![];
624 for (ns_id, ns) in self.namespaces.iter().enumerate() {
625 for (id, _type_) in ns.types.iter().enumerate() {
626 let type_id = TypeId {
627 ns_id: ns_id as u16,
628 id: id as u32,
629 };
630
631 match self.type_(type_id) {
632 Type::Bitfield(Bitfield { name, members, .. })
633 | Type::Enumeration(Enumeration { name, members, .. }) => {
634 let full_name = format!("{}.{}", ns.name, name);
635 let config = config.objects.get(&full_name);
636 let mut type_members = HashMap::new();
637 for member in members.iter() {
638 let status = config.and_then(|m| {
639 m.members.matched(&member.name).first().map(|m| m.status)
640 });
641 type_members.insert(member.c_identifier.clone(), status);
642 }
643 members_to_change.push((type_id, type_members));
644 }
645 _ => (),
646 };
647 }
648 }
649
650 for (type_id, item_members) in members_to_change {
651 match self.type_mut(type_id) {
652 Type::Bitfield(Bitfield { members, .. })
653 | Type::Enumeration(Enumeration { members, .. }) => {
654 for member in members.iter_mut() {
655 let status = item_members
656 .get(&member.c_identifier)
657 .copied()
658 .flatten()
659 .unwrap_or(GStatus::Generate);
660 member.status = status;
661 }
662 }
663 _ => (),
664 };
665 }
666 }
667}