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 if is_empty_c_type(par.c_type())
82 && let Some(s) = c_types.get(&par.typ())
83 {
84 par.set_c_type(s);
85 }
86 }
87 if is_empty_c_type(signal.ret.c_type())
88 && let Some(s) = c_types.get(&signal.ret.typ())
89 {
90 signal.ret.set_c_type(s);
91 }
92 }
93
94 let mut tids = Vec::new();
95 let mut c_types = DetectedCTypes::new();
96 for (ns_id, ns) in self.namespaces.iter().enumerate() {
97 for (id, type_) in ns.types.iter().enumerate() {
98 let type_ = type_.as_ref().unwrap(); let tid = TypeId {
100 ns_id: ns_id as u16,
101 id: id as u32,
102 };
103 match type_ {
104 Type::Class(klass)
105 if self.detect_empty_signals_c_types(&klass.signals, &mut c_types) =>
106 {
107 tids.push(tid);
108 }
109 Type::Interface(iface)
110 if self.detect_empty_signals_c_types(&iface.signals, &mut c_types) =>
111 {
112 tids.push(tid);
113 }
114 _ => (),
115 }
116 }
117 }
118
119 for tid in tids {
120 match self.type_mut(tid) {
121 Type::Class(klass) => update_empty_signals_c_types(&mut klass.signals, &c_types),
122 Type::Interface(iface) => {
123 update_empty_signals_c_types(&mut iface.signals, &c_types);
124 }
125 _ => (),
126 }
127 }
128 }
129
130 fn detect_empty_signals_c_types(
131 &self,
132 signals: &[Signal],
133 c_types: &mut DetectedCTypes,
134 ) -> bool {
135 let mut detected = false;
136 for signal in signals {
137 if self.detect_empty_signal_c_types(signal, c_types) {
138 detected = true;
139 }
140 }
141 detected
142 }
143
144 fn detect_empty_signal_c_types(&self, signal: &Signal, c_types: &mut DetectedCTypes) -> bool {
145 let mut detected = false;
146 for par in &signal.parameters {
147 if self.detect_empty_c_type(par.c_type(), par.typ(), c_types) {
148 detected = true;
149 }
150 }
151 if self.detect_empty_c_type(signal.ret.c_type(), signal.ret.typ(), c_types) {
152 detected = true;
153 }
154 detected
155 }
156
157 fn detect_empty_c_type(&self, c_type: &str, tid: TypeId, c_types: &mut DetectedCTypes) -> bool {
158 if !is_empty_c_type(c_type) {
159 return false;
160 }
161 if let std::collections::hash_map::Entry::Vacant(entry) = c_types.entry(tid)
162 && let Some(detected_c_type) = self.c_type_by_type_id(tid)
163 {
164 entry.insert(detected_c_type);
165 }
166 true
167 }
168
169 fn c_type_by_type_id(&self, tid: TypeId) -> Option<String> {
170 let type_ = self.type_(tid);
171 type_.get_glib_name().map(|glib_name| {
172 if self.is_referenced_type(type_) {
173 format!("{glib_name}*")
174 } else {
175 glib_name.to_string()
176 }
177 })
178 }
179
180 fn is_referenced_type(&self, type_: &Type) -> bool {
181 use crate::library::Type::*;
182 match type_ {
183 Alias(alias) => self.is_referenced_type(self.type_(alias.typ)),
184 Record(..) | Union(..) | Class(..) | Interface(..) => true,
185 _ => false,
186 }
187 }
188
189 fn resolve_class_structs(&mut self) {
190 let mut structs_and_types = Vec::new();
192
193 for (ns_id, ns) in self.namespaces.iter().enumerate() {
194 for type_ in &ns.types {
195 let type_ = type_.as_ref().unwrap(); if let Type::Record(record) = type_
198 && let Some(ref struct_for) = record.gtype_struct_for
199 && let Some(struct_for_tid) = self.find_type(ns_id as u16, struct_for)
200 {
201 structs_and_types.push((record.c_type.clone(), struct_for_tid));
202 }
203 }
204 }
205
206 for (gtype_struct_c_type, struct_for_tid) in structs_and_types {
207 match self.type_mut(struct_for_tid) {
208 Type::Class(klass) => {
209 klass.c_class_type = Some(gtype_struct_c_type);
210 }
211
212 Type::Interface(iface) => {
213 iface.c_class_type = Some(gtype_struct_c_type);
214 }
215
216 x => unreachable!(
217 "Something other than a class or interface has a class struct: {:?}",
218 x
219 ),
220 }
221 }
222 }
223
224 fn correlate_class_structs(&self) {
225 for (ns_id, ns) in self.namespaces.iter().enumerate() {
226 for type_ in &ns.types {
227 let type_ = type_.as_ref().unwrap(); let (name, type_struct, c_class_type) = match type_ {
230 Type::Class(klass) => (&klass.name, &klass.type_struct, &klass.c_class_type),
231
232 Type::Interface(iface) => {
233 (&iface.name, &iface.type_struct, &iface.c_class_type)
234 }
235
236 _ => {
237 continue;
238 }
239 };
240
241 if let Some(type_struct) = type_struct {
242 let type_struct_tid = self.find_type(ns_id as u16, type_struct);
243 assert!(
244 type_struct_tid.is_some(),
245 "\"{name}\" has glib:type-struct=\"{type_struct}\" but there is no such record"
246 );
247
248 let type_struct_type = self.type_(type_struct_tid.unwrap());
249
250 if let Type::Record(r) = type_struct_type {
251 if r.gtype_struct_for.as_ref() != Some(name) {
252 if let Some(ref gtype_struct_for) = r.gtype_struct_for {
253 panic!(
254 "\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
255 name, type_struct, r.name, gtype_struct_for
256 );
257 } else {
258 panic!(
259 "\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
260 name, type_struct, r.name
261 );
262 }
263 }
264 } else {
265 panic!(
266 "Element with name=\"{type_struct}\" should be a record but it isn't"
267 );
268 }
269 } else if let Some(c) = c_class_type {
270 panic!(
271 "\"{name}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{c}\""
272 );
273 }
274 }
278 }
279 }
280
281 fn fix_fields(&mut self) {
282 enum Action {
283 SetCType(String),
284 SetName(String),
285 }
286 let mut actions: Vec<(TypeId, usize, Action)> = Vec::new();
287 for (ns_id, ns) in self.namespaces.iter().enumerate() {
288 for (id, type_) in ns.types.iter().enumerate() {
289 let type_ = type_.as_ref().unwrap(); let tid = TypeId {
291 ns_id: ns_id as u16,
292 id: id as u32,
293 };
294 match type_ {
295 Type::Class(Class { name, fields, .. })
296 | Type::Record(Record { name, fields, .. })
297 | Type::Union(Union { name, fields, .. }) => {
298 for (fid, field) in fields.iter().enumerate() {
299 if nameutil::needs_mangling(&field.name) {
300 let new_name = nameutil::mangle_keywords(&*field.name).into_owned();
301 actions.push((tid, fid, Action::SetName(new_name)));
302 }
303 if field.c_type.is_some() {
304 continue;
305 }
306 let field_type = self.type_(field.typ);
307 if field_type.maybe_ref_as::<Function>().is_some() {
308 continue;
310 }
311 if let Some(c_type) = field_type.get_glib_name() {
312 actions.push((tid, fid, Action::SetCType(c_type.to_owned())));
313 continue;
314 }
315 if let Type::Basic(Basic::Pointer) = field_type {
316 actions.push((tid, fid, Action::SetCType("void*".to_owned())));
318 continue;
319 }
320 if let Type::FixedArray(..) = field_type {
321 let array_c_type = "fixed_array".to_owned();
325 actions.push((tid, fid, Action::SetCType(array_c_type)));
326 continue;
327 }
328 if let Type::CArray(..) = field_type {
329 let array_c_type = "c_array".to_owned();
334 actions.push((tid, fid, Action::SetCType(array_c_type)));
335 continue;
336 }
337 error!("Field `{}::{}` is missing c:type", name, field.name);
338 }
339 }
340 _ => {}
341 }
342 }
343 }
344 let ignore_missing_ctype = ["padding", "reserved", "_padding", "_reserved"];
345 for (tid, fid, action) in actions {
346 match self.type_mut(tid) {
347 Type::Class(Class { name, fields, .. })
348 | Type::Record(Record { name, fields, .. })
349 | Type::Union(Union { name, fields, .. }) => match action {
350 Action::SetCType(c_type) => {
351 if !ignore_missing_ctype.contains(&fields[fid].name.as_str()) {
354 warn_main!(
355 tid,
356 "Field `{}::{}` missing c:type assumed to be `{}`",
357 name,
358 &fields[fid].name,
359 c_type
360 );
361 }
362 fields[fid].c_type = Some(c_type);
363 }
364 Action::SetName(name) => fields[fid].name = name,
365 },
366 _ => unreachable!("Expected class, record or union"),
367 }
368 }
369 }
370
371 fn make_unrepresentable_types_opaque(&mut self) {
372 let mut unrepresentable: Vec<TypeId> = Vec::new();
381 for (ns_id, ns) in self.namespaces.iter().enumerate() {
382 for (id, type_) in ns.types.iter().enumerate() {
383 let type_ = type_.as_ref().unwrap();
384 let tid = TypeId {
385 ns_id: ns_id as u16,
386 id: id as u32,
387 };
388 match type_ {
389 Type::Union(Union { fields, .. }) if fields.as_slice().is_incomplete(self) => {
390 unrepresentable.push(tid);
391 }
392 _ => {}
393 }
394 }
395 }
396 for tid in unrepresentable {
397 match self.type_mut(tid) {
398 Type::Union(Union { name, fields, .. }) => {
399 info!("Type `{name}` is not representable.");
400 fields.clear();
401 }
402 _ => unreachable!("Expected a union"),
403 }
404 }
405 }
406
407 fn has_subtypes(&self, parent_tid: TypeId) -> bool {
408 for (tid, _) in self.types() {
409 if let Type::Class(class) = self.type_(tid)
410 && class.parent == Some(parent_tid)
411 {
412 return true;
413 }
414 }
415
416 false
417 }
418
419 fn mark_final_types(&mut self, config: &Config) {
420 let mut overridden_final_types: Vec<(TypeId, bool)> = Vec::new();
430
431 for (ns_id, ns) in self.namespaces.iter().enumerate() {
432 for (id, type_) in ns.types.iter().enumerate() {
433 let type_ = type_.as_ref().unwrap(); if let Type::Class(klass) = type_ {
436 let tid = TypeId {
437 ns_id: ns_id as u16,
438 id: id as u32,
439 };
440
441 let full_name = tid.full_name(self);
442 let obj = config.objects.get(&*full_name);
443
444 if let Some(GObject {
445 final_type: Some(final_type),
446 ..
447 }) = obj
448 {
449 overridden_final_types.push((tid, *final_type));
452 } else if klass.final_type {
453 continue;
454 } else if klass.type_struct.is_none() {
455 let is_final = !self.has_subtypes(tid);
456 if is_final {
457 overridden_final_types.push((tid, true));
458 }
459 } else {
460 let has_subtypes = self.has_subtypes(tid);
461 let instance_struct_known = !klass.fields.is_empty();
462
463 let class_struct_known = if let Some(class_record_tid) =
464 self.find_type(ns_id as u16, klass.type_struct.as_ref().unwrap())
465 {
466 if let Type::Record(record) = self.type_(class_record_tid) {
467 !record.disguised && !record.pointer
468 } else {
469 unreachable!("Type {} with non-record class", full_name);
470 }
471 } else {
472 unreachable!("Can't find class for {}", full_name);
473 };
474
475 let is_final =
476 !has_subtypes && (!instance_struct_known || !class_struct_known);
477 if is_final {
478 overridden_final_types.push((tid, true));
479 }
480 };
481 }
482 }
483 }
484
485 for (tid, new_is_final) in overridden_final_types {
486 if let Type::Class(Class { final_type, .. }) = self.type_mut(tid) {
487 *final_type = new_is_final;
488 } else {
489 unreachable!();
490 }
491 }
492 }
493
494 fn update_error_domain_functions(&mut self, config: &Config) {
495 let mut error_domains = vec![];
497 for (ns_id, ns) in self.namespaces.iter().enumerate() {
498 'next_enum: for (id, type_) in ns.types.iter().enumerate() {
499 let type_ = type_.as_ref().unwrap(); let enum_tid = TypeId {
501 ns_id: ns_id as u16,
502 id: id as u32,
503 };
504
505 if let Type::Enumeration(enum_) = type_
506 && let Some(ErrorDomain::Quark(ref domain)) = enum_.error_domain
507 {
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
530 .functions
531 .iter()
532 .find(|f| function_candidates.iter().any(|c| &f.c_identifier == c))
533 {
534 error_domains.push((ns_id, enum_tid, None, func.c_identifier.clone()));
535 continue 'next_enum;
536 }
537
538 for (id, type_) in ns.types.iter().enumerate() {
540 let type_ = type_.as_ref().unwrap(); let domain_tid = TypeId {
542 ns_id: ns_id as u16,
543 id: id as u32,
544 };
545
546 let functions = match type_ {
547 Type::Enumeration(Enumeration { functions, .. })
548 | Type::Class(Class { functions, .. })
549 | Type::Record(Record { functions, .. })
550 | Type::Interface(Interface { functions, .. }) => functions,
551 _ => continue,
552 };
553
554 if let Some(func) = functions
555 .iter()
556 .find(|f| function_candidates.iter().any(|c| &f.c_identifier == c))
557 {
558 error_domains.push((
559 ns_id,
560 enum_tid,
561 Some(domain_tid),
562 func.c_identifier.clone(),
563 ));
564 continue 'next_enum;
565 }
566 }
567 }
568 }
569 }
570
571 for (ns_id, enum_tid, domain_tid, function_name) in error_domains {
572 if config.work_mode != WorkMode::Sys {
573 if let Some(domain_tid) = domain_tid {
574 match self.type_mut(domain_tid) {
575 Type::Enumeration(Enumeration { functions, .. })
576 | Type::Class(Class { functions, .. })
577 | Type::Record(Record { functions, .. })
578 | Type::Interface(Interface { functions, .. }) => {
579 let pos = functions
580 .iter()
581 .position(|f| f.c_identifier == function_name)
582 .unwrap();
583 functions.remove(pos);
584 }
585 _ => unreachable!(),
586 }
587 } else {
588 let pos = self.namespaces[ns_id]
589 .functions
590 .iter()
591 .position(|f| f.c_identifier == function_name)
592 .unwrap();
593 self.namespaces[ns_id].functions.remove(pos);
594 }
595 }
596
597 if let Type::Enumeration(enum_) = self.type_mut(enum_tid) {
598 assert!(enum_.error_domain.is_some());
599 enum_.error_domain = Some(ErrorDomain::Function(function_name));
600 } else {
601 unreachable!();
602 }
603 }
604 }
605
606 fn mark_ignored_enum_members(&mut self, config: &Config) {
607 let mut members_to_change = vec![];
608 for (ns_id, ns) in self.namespaces.iter().enumerate() {
609 for (id, _type_) in ns.types.iter().enumerate() {
610 let type_id = TypeId {
611 ns_id: ns_id as u16,
612 id: id as u32,
613 };
614
615 match self.type_(type_id) {
616 Type::Bitfield(Bitfield { name, members, .. })
617 | Type::Enumeration(Enumeration { name, members, .. }) => {
618 let full_name = format!("{}.{}", ns.name, name);
619 let config = config.objects.get(&full_name);
620 let mut type_members = HashMap::new();
621 for member in members.iter() {
622 let status = config.and_then(|m| {
623 m.members.matched(&member.name).first().map(|m| m.status)
624 });
625 type_members.insert(member.c_identifier.clone(), status);
626 }
627 members_to_change.push((type_id, type_members));
628 }
629 _ => (),
630 };
631 }
632 }
633
634 for (type_id, item_members) in members_to_change {
635 match self.type_mut(type_id) {
636 Type::Bitfield(Bitfield { members, .. })
637 | Type::Enumeration(Enumeration { members, .. }) => {
638 for member in members.iter_mut() {
639 let status = item_members
640 .get(&member.c_identifier)
641 .copied()
642 .flatten()
643 .unwrap_or(GStatus::Generate);
644 member.status = status;
645 }
646 }
647 _ => (),
648 };
649 }
650 }
651}