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;
229 let type_struct;
230 let c_class_type;
231
232 match type_ {
233 Type::Class(klass) => {
234 name = &klass.name;
235 type_struct = &klass.type_struct;
236 c_class_type = &klass.c_class_type;
237 }
238
239 Type::Interface(iface) => {
240 name = &iface.name;
241 type_struct = &iface.type_struct;
242 c_class_type = &iface.c_class_type;
243 }
244
245 _ => {
246 continue;
247 }
248 }
249
250 if let Some(type_struct) = type_struct {
251 let type_struct_tid = self.find_type(ns_id as u16, type_struct);
252 assert!(
253 type_struct_tid.is_some(),
254 "\"{name}\" has glib:type-struct=\"{type_struct}\" but there is no such record"
255 );
256
257 let type_struct_type = self.type_(type_struct_tid.unwrap());
258
259 if let Type::Record(r) = type_struct_type {
260 if r.gtype_struct_for.as_ref() != Some(name) {
261 if let Some(ref gtype_struct_for) = r.gtype_struct_for {
262 panic!(
263 "\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has glib:is-gtype-struct-for={:?}",
264 name, type_struct, r.name, gtype_struct_for
265 );
266 } else {
267 panic!(
268 "\"{}\" has glib:type-struct=\"{}\" but the corresponding record \"{}\" has no glib:is-gtype-struct-for attribute",
269 name, type_struct, r.name
270 );
271 }
272 }
273 } else {
274 panic!(
275 "Element with name=\"{type_struct}\" should be a record but it isn't"
276 );
277 }
278 } else if let Some(c) = c_class_type {
279 panic!(
280 "\"{name}\" has no glib:type-struct but there is an element with glib:is-gtype-struct-for=\"{c}\""
281 );
282 }
283 }
287 }
288 }
289
290 fn fix_fields(&mut self) {
291 enum Action {
292 SetCType(String),
293 SetName(String),
294 }
295 let mut actions: Vec<(TypeId, usize, Action)> = Vec::new();
296 for (ns_id, ns) in self.namespaces.iter().enumerate() {
297 for (id, type_) in ns.types.iter().enumerate() {
298 let type_ = type_.as_ref().unwrap(); let tid = TypeId {
300 ns_id: ns_id as u16,
301 id: id as u32,
302 };
303 match type_ {
304 Type::Class(Class { name, fields, .. })
305 | Type::Record(Record { name, fields, .. })
306 | Type::Union(Union { name, fields, .. }) => {
307 for (fid, field) in fields.iter().enumerate() {
308 if nameutil::needs_mangling(&field.name) {
309 let new_name = nameutil::mangle_keywords(&*field.name).into_owned();
310 actions.push((tid, fid, Action::SetName(new_name)));
311 }
312 if field.c_type.is_some() {
313 continue;
314 }
315 let field_type = self.type_(field.typ);
316 if field_type.maybe_ref_as::<Function>().is_some() {
317 continue;
319 }
320 if let Some(c_type) = field_type.get_glib_name() {
321 actions.push((tid, fid, Action::SetCType(c_type.to_owned())));
322 continue;
323 }
324 if let Type::Basic(Basic::Pointer) = field_type {
325 actions.push((tid, fid, Action::SetCType("void*".to_owned())));
327 continue;
328 }
329 if let Type::FixedArray(..) = field_type {
330 let array_c_type = "fixed_array".to_owned();
334 actions.push((tid, fid, Action::SetCType(array_c_type)));
335 continue;
336 }
337 if let Type::CArray(..) = field_type {
338 let array_c_type = "c_array".to_owned();
343 actions.push((tid, fid, Action::SetCType(array_c_type)));
344 continue;
345 }
346 error!("Field `{}::{}` is missing c:type", name, &field.name);
347 }
348 }
349 _ => {}
350 }
351 }
352 }
353 let ignore_missing_ctype = ["padding", "reserved", "_padding", "_reserved"];
354 for (tid, fid, action) in actions {
355 match self.type_mut(tid) {
356 Type::Class(Class { name, fields, .. })
357 | Type::Record(Record { name, fields, .. })
358 | Type::Union(Union { name, fields, .. }) => match action {
359 Action::SetCType(c_type) => {
360 if !ignore_missing_ctype.contains(&fields[fid].name.as_str()) {
363 warn_main!(
364 tid,
365 "Field `{}::{}` missing c:type assumed to be `{}`",
366 name,
367 &fields[fid].name,
368 c_type
369 );
370 }
371 fields[fid].c_type = Some(c_type);
372 }
373 Action::SetName(name) => fields[fid].name = name,
374 },
375 _ => unreachable!("Expected class, record or union"),
376 }
377 }
378 }
379
380 fn make_unrepresentable_types_opaque(&mut self) {
381 let mut unrepresentable: Vec<TypeId> = Vec::new();
390 for (ns_id, ns) in self.namespaces.iter().enumerate() {
391 for (id, type_) in ns.types.iter().enumerate() {
392 let type_ = type_.as_ref().unwrap();
393 let tid = TypeId {
394 ns_id: ns_id as u16,
395 id: id as u32,
396 };
397 match type_ {
398 Type::Union(Union { fields, .. }) if fields.as_slice().is_incomplete(self) => {
399 unrepresentable.push(tid);
400 }
401 _ => {}
402 }
403 }
404 }
405 for tid in unrepresentable {
406 match self.type_mut(tid) {
407 Type::Union(Union { name, fields, .. }) => {
408 info!("Type `{name}` is not representable.");
409 fields.clear();
410 }
411 _ => unreachable!("Expected a union"),
412 }
413 }
414 }
415
416 fn has_subtypes(&self, parent_tid: TypeId) -> bool {
417 for (tid, _) in self.types() {
418 if let Type::Class(class) = self.type_(tid)
419 && class.parent == Some(parent_tid)
420 {
421 return true;
422 }
423 }
424
425 false
426 }
427
428 fn mark_final_types(&mut self, config: &Config) {
429 let mut overridden_final_types: Vec<(TypeId, bool)> = Vec::new();
439
440 for (ns_id, ns) in self.namespaces.iter().enumerate() {
441 for (id, type_) in ns.types.iter().enumerate() {
442 let type_ = type_.as_ref().unwrap(); if let Type::Class(klass) = type_ {
445 let tid = TypeId {
446 ns_id: ns_id as u16,
447 id: id as u32,
448 };
449
450 let full_name = tid.full_name(self);
451 let obj = config.objects.get(&*full_name);
452
453 if let Some(GObject {
454 final_type: Some(final_type),
455 ..
456 }) = obj
457 {
458 overridden_final_types.push((tid, *final_type));
461 } else if klass.final_type {
462 continue;
463 } else if klass.type_struct.is_none() {
464 let is_final = !self.has_subtypes(tid);
465 if is_final {
466 overridden_final_types.push((tid, true));
467 }
468 } else {
469 let has_subtypes = self.has_subtypes(tid);
470 let instance_struct_known = !klass.fields.is_empty();
471
472 let class_struct_known = if let Some(class_record_tid) =
473 self.find_type(ns_id as u16, klass.type_struct.as_ref().unwrap())
474 {
475 if let Type::Record(record) = self.type_(class_record_tid) {
476 !record.disguised && !record.pointer
477 } else {
478 unreachable!("Type {} with non-record class", full_name);
479 }
480 } else {
481 unreachable!("Can't find class for {}", full_name);
482 };
483
484 let is_final =
485 !has_subtypes && (!instance_struct_known || !class_struct_known);
486 if is_final {
487 overridden_final_types.push((tid, true));
488 }
489 };
490 }
491 }
492 }
493
494 for (tid, new_is_final) in overridden_final_types {
495 if let Type::Class(Class { final_type, .. }) = self.type_mut(tid) {
496 *final_type = new_is_final;
497 } else {
498 unreachable!();
499 }
500 }
501 }
502
503 fn update_error_domain_functions(&mut self, config: &Config) {
504 let mut error_domains = vec![];
506 for (ns_id, ns) in self.namespaces.iter().enumerate() {
507 'next_enum: for (id, type_) in ns.types.iter().enumerate() {
508 let type_ = type_.as_ref().unwrap(); let enum_tid = TypeId {
510 ns_id: ns_id as u16,
511 id: id as u32,
512 };
513
514 if let Type::Enumeration(enum_) = type_
515 && let Some(ErrorDomain::Quark(ref domain)) = enum_.error_domain
516 {
517 let domain = domain.replace('-', "_");
518
519 let mut function_candidates = vec![domain.clone()];
520 if !domain.ends_with("_quark") {
521 function_candidates.push(format!("{domain}_quark"));
522 }
523 if !domain.ends_with("_error_quark") {
524 if domain.ends_with("_quark") {
525 function_candidates
526 .push(format!("{}_error_quark", &domain[..(domain.len() - 6)]));
527 } else {
528 function_candidates.push(format!("{domain}_error_quark"));
529 }
530 }
531 if let Some(domain) = domain.strip_suffix("_error_quark") {
532 function_candidates.push(domain.to_owned());
533 }
534 if let Some(domain) = domain.strip_suffix("_quark") {
535 function_candidates.push(domain.to_owned());
536 }
537
538 if let Some(func) = ns
539 .functions
540 .iter()
541 .find(|f| function_candidates.iter().any(|c| &f.c_identifier == c))
542 {
543 error_domains.push((ns_id, enum_tid, None, func.c_identifier.clone()));
544 continue 'next_enum;
545 }
546
547 for (id, type_) in ns.types.iter().enumerate() {
549 let type_ = type_.as_ref().unwrap(); let domain_tid = TypeId {
551 ns_id: ns_id as u16,
552 id: id as u32,
553 };
554
555 let functions = match type_ {
556 Type::Enumeration(Enumeration { functions, .. })
557 | Type::Class(Class { functions, .. })
558 | Type::Record(Record { functions, .. })
559 | Type::Interface(Interface { functions, .. }) => functions,
560 _ => continue,
561 };
562
563 if let Some(func) = functions
564 .iter()
565 .find(|f| function_candidates.iter().any(|c| &f.c_identifier == c))
566 {
567 error_domains.push((
568 ns_id,
569 enum_tid,
570 Some(domain_tid),
571 func.c_identifier.clone(),
572 ));
573 continue 'next_enum;
574 }
575 }
576 }
577 }
578 }
579
580 for (ns_id, enum_tid, domain_tid, function_name) in error_domains {
581 if config.work_mode != WorkMode::Sys {
582 if let Some(domain_tid) = domain_tid {
583 match self.type_mut(domain_tid) {
584 Type::Enumeration(Enumeration { functions, .. })
585 | Type::Class(Class { functions, .. })
586 | Type::Record(Record { functions, .. })
587 | Type::Interface(Interface { functions, .. }) => {
588 let pos = functions
589 .iter()
590 .position(|f| f.c_identifier == function_name)
591 .unwrap();
592 functions.remove(pos);
593 }
594 _ => unreachable!(),
595 }
596 } else {
597 let pos = self.namespaces[ns_id]
598 .functions
599 .iter()
600 .position(|f| f.c_identifier == function_name)
601 .unwrap();
602 self.namespaces[ns_id].functions.remove(pos);
603 }
604 }
605
606 if let Type::Enumeration(enum_) = self.type_mut(enum_tid) {
607 assert!(enum_.error_domain.is_some());
608 enum_.error_domain = Some(ErrorDomain::Function(function_name));
609 } else {
610 unreachable!();
611 }
612 }
613 }
614
615 fn mark_ignored_enum_members(&mut self, config: &Config) {
616 let mut members_to_change = vec![];
617 for (ns_id, ns) in self.namespaces.iter().enumerate() {
618 for (id, _type_) in ns.types.iter().enumerate() {
619 let type_id = TypeId {
620 ns_id: ns_id as u16,
621 id: id as u32,
622 };
623
624 match self.type_(type_id) {
625 Type::Bitfield(Bitfield { name, members, .. })
626 | Type::Enumeration(Enumeration { name, members, .. }) => {
627 let full_name = format!("{}.{}", ns.name, name);
628 let config = config.objects.get(&full_name);
629 let mut type_members = HashMap::new();
630 for member in members.iter() {
631 let status = config.and_then(|m| {
632 m.members.matched(&member.name).first().map(|m| m.status)
633 });
634 type_members.insert(member.c_identifier.clone(), status);
635 }
636 members_to_change.push((type_id, type_members));
637 }
638 _ => (),
639 };
640 }
641 }
642
643 for (type_id, item_members) in members_to_change {
644 match self.type_mut(type_id) {
645 Type::Bitfield(Bitfield { members, .. })
646 | Type::Enumeration(Enumeration { members, .. }) => {
647 for member in members.iter_mut() {
648 let status = item_members
649 .get(&member.c_identifier)
650 .copied()
651 .flatten()
652 .unwrap_or(GStatus::Generate);
653 member.status = status;
654 }
655 }
656 _ => (),
657 };
658 }
659 }
660}