Skip to content

Commit 9130a2d

Browse files
committed
Redo how init methods from superclasses are propagated to subclasses
This currently removes a few methods, but is strictly more correct, especially in the location of category methods.
1 parent 59fd73f commit 9130a2d

File tree

7 files changed

+157
-195
lines changed

7 files changed

+157
-195
lines changed

crates/header-translator/src/cache.rs

Lines changed: 3 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,99 +1,22 @@
11
use std::collections::BTreeMap;
22
use std::mem;
33

4-
use crate::availability::Availability;
5-
use crate::config::{ClassData, Config};
4+
use crate::config::Config;
65
use crate::file::File;
76
use crate::id::ItemIdentifier;
87
use crate::method::Method;
98
use crate::output::Output;
109
use crate::stmt::Stmt;
1110

12-
#[derive(Debug, PartialEq, Clone)]
13-
struct MethodCache {
14-
availability: Availability,
15-
methods: Vec<Method>,
16-
category: ItemIdentifier<Option<String>>,
17-
}
18-
19-
#[derive(Debug, PartialEq, Clone, Default)]
20-
struct ClassCache {
21-
/// Methods that should be duplicated onto any subclass.
22-
to_emit: Vec<MethodCache>,
23-
// We don't need availability here, since a superclass' availability
24-
// should always be greater than the subclass'.
25-
}
26-
27-
impl ClassCache {
28-
fn all_methods_data(&self) -> impl Iterator<Item = (bool, &str)> {
29-
self.to_emit
30-
.iter()
31-
.flat_map(|cache| cache.methods.iter().map(|m| m.id()))
32-
}
33-
}
34-
3511
/// A helper struct for doing global analysis on the output.
3612
#[derive(Debug, PartialEq, Clone)]
3713
pub struct Cache<'a> {
38-
classes: BTreeMap<ItemIdentifier, ClassCache>,
3914
config: &'a Config,
4015
}
4116

4217
impl<'a> Cache<'a> {
43-
pub fn new(output: &Output, config: &'a Config) -> Self {
44-
let mut classes: BTreeMap<_, ClassCache> = BTreeMap::new();
45-
46-
for (name, library) in &output.libraries {
47-
let _span = debug_span!("library", name).entered();
48-
for (name, file) in &library.files {
49-
let _span = debug_span!("file", name).entered();
50-
for stmt in &file.stmts {
51-
if let Some((cls, method_cache)) = Self::cache_stmt(stmt) {
52-
let cache = classes.entry(cls.clone()).or_default();
53-
cache.to_emit.push(method_cache);
54-
}
55-
}
56-
}
57-
}
58-
59-
Self { classes, config }
60-
}
61-
62-
fn cache_stmt(stmt: &Stmt) -> Option<(&ItemIdentifier, MethodCache)> {
63-
if let Stmt::Methods {
64-
cls,
65-
generics: _,
66-
category,
67-
availability,
68-
superclasses: _,
69-
methods,
70-
description,
71-
} = stmt
72-
{
73-
let _span = debug_span!("Stmt::Methods", ?cls).entered();
74-
let methods: Vec<Method> = methods
75-
.iter()
76-
.filter(|method| method.emit_on_subclasses())
77-
.cloned()
78-
.collect();
79-
if methods.is_empty() {
80-
return None;
81-
}
82-
if description.is_some() {
83-
warn!(description, "description was set");
84-
}
85-
let category = category.clone().with_new_path(cls);
86-
Some((
87-
cls,
88-
MethodCache {
89-
availability: availability.clone(),
90-
methods,
91-
category,
92-
},
93-
))
94-
} else {
95-
None
96-
}
18+
pub fn new(_output: &Output, config: &'a Config) -> Self {
19+
Self { config }
9720
}
9821

9922
pub fn update(&self, output: &mut Output) {
@@ -145,70 +68,6 @@ impl<'a> Cache<'a> {
14568
}
14669
}
14770

148-
let mut new_stmts = Vec::new();
149-
for stmt in &mut file.stmts {
150-
#[allow(clippy::single_match)] // There will be others
151-
match stmt {
152-
Stmt::ClassDecl {
153-
id,
154-
generics,
155-
superclasses,
156-
..
157-
} => {
158-
let _span = debug_span!("Stmt::ClassDecl", ?id).entered();
159-
let data = self.config.class_data.get(&id.name);
160-
161-
// Used for duplicate checking (sometimes the subclass
162-
// defines the same method that the superclass did).
163-
let mut seen_methods: Vec<_> = self
164-
.classes
165-
.get(id)
166-
.map(|cache| cache.all_methods_data())
167-
.into_iter()
168-
.flatten()
169-
.collect();
170-
171-
for (superclass, _) in &*superclasses {
172-
if let Some(cache) = self.classes.get(superclass) {
173-
new_stmts.extend(cache.to_emit.iter().filter_map(|cache| {
174-
let methods: Vec<_> = cache
175-
.methods
176-
.iter()
177-
.filter(|method| !seen_methods.contains(&method.id()))
178-
.filter_map(|method| {
179-
method.clone().update(ClassData::get_method_data(
180-
data,
181-
&method.fn_name,
182-
))
183-
})
184-
.collect();
185-
if methods.is_empty() {
186-
return None;
187-
}
188-
189-
Some(Stmt::Methods {
190-
cls: id.clone(),
191-
generics: generics.clone(),
192-
category: cache.category.clone(),
193-
availability: cache.availability.clone(),
194-
superclasses: superclasses.clone(),
195-
methods,
196-
description: Some(format!(
197-
"Methods declared on superclass `{}`",
198-
superclass.name
199-
)),
200-
})
201-
}));
202-
203-
seen_methods.extend(cache.all_methods_data());
204-
}
205-
}
206-
}
207-
_ => {}
208-
}
209-
}
210-
file.stmts.extend(new_stmts);
211-
21271
// Fix up a few typedef + enum declarations
21372
let mut iter = mem::take(&mut file.stmts).into_iter().peekable();
21473
while let Some(stmt) = iter.next() {

crates/header-translator/src/config.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,17 @@ pub struct MethodData {
157157
pub mutating: Option<bool>,
158158
}
159159

160+
impl MethodData {
161+
pub(crate) fn merge_with_superclass(self, superclass: Self) -> Self {
162+
Self {
163+
// Only use `unsafe` from itself, never take if from the superclass
164+
unsafe_: self.unsafe_,
165+
skipped: self.skipped | superclass.skipped,
166+
mutating: self.mutating.or(superclass.mutating),
167+
}
168+
}
169+
}
170+
160171
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
161172
#[serde(deny_unknown_fields)]
162173
pub struct FnData {

crates/header-translator/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ fn main() -> Result<(), BoxError> {
178178
}
179179
writeln!(cargo_toml, "]")?;
180180
}
181+
drop(cargo_toml);
181182
drop(span);
182183

183184
let _span = info_span!("formatting").entered();

crates/header-translator/src/method.rs

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,8 @@ pub struct Method {
242242

243243
impl Method {
244244
/// Value that uniquely identifies the method in a class.
245-
pub fn id(&self) -> (bool, &str) {
246-
(self.is_class, &self.selector)
245+
pub fn id(&self) -> (bool, String) {
246+
(self.is_class, self.selector.clone())
247247
}
248248

249249
fn parent_type_data(entity: &Entity<'_>, context: &Context<'_>) -> (bool, bool) {
@@ -320,17 +320,6 @@ impl Method {
320320
}
321321
}
322322

323-
pub fn update(mut self, data: MethodData) -> Option<Self> {
324-
if data.skipped {
325-
return None;
326-
}
327-
328-
self.mutating = data.mutating.unwrap_or(false);
329-
self.safe = !data.unsafe_;
330-
331-
Some(self)
332-
}
333-
334323
pub fn visit_required_types(&self, mut f: impl FnMut(&ItemIdentifier)) {
335324
for (_, arg) in &self.arguments {
336325
arg.visit_required_types(&mut f);

0 commit comments

Comments
 (0)