sphinx_rustdocgen/directives/
mod.rs

1// sphinxcontrib_rust - Sphinx extension for the Rust programming language
2// Copyright (C) 2024  Munir Contractor
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17//! Module for the various Sphinx directives for the Rust domain.
18//!
19//! The module primarily provides the :rust:enum:`Directive`, which implements
20//! the various directives using directive specific structs. The enum and all
21//! directive specific structs implement both
22//! :rust:trait:`~sphinx_rustdocgen::formats::RstContent` and
23//! :rust:trait:`~sphinx_rustdocgen::formats::MdContent` traits.
24//! It also provides the :rust:enum:`DirectiveOption` enum, which
25//! implements the various options of the directive.
26//!
27//! The output of the directives is parsed by the
28//! :py:class:`sphinxcontrib_rust.directives.RustDirective` within the Python
29//! extension.
30
31mod crate_directive;
32mod directive_options;
33mod enum_directive;
34mod executable_directive;
35mod function_directive;
36mod impl_directive;
37mod macro_directive;
38mod module_directive;
39mod struct_directive;
40mod trait_directive;
41mod type_directive;
42mod use_directive;
43mod variable_directive;
44
45use syn::{Attribute, Expr, ForeignItem, ImplItem, Item, Lit, TraitItem, Visibility};
46
47// Re-exports are mainly for testing
48pub use crate::directives::crate_directive::CrateDirective;
49pub(crate) use crate::directives::directive_options::DirectiveVisibility;
50pub use crate::directives::enum_directive::EnumDirective;
51pub use crate::directives::executable_directive::ExecutableDirective;
52pub use crate::directives::function_directive::FunctionDirective;
53pub use crate::directives::impl_directive::ImplDirective;
54pub use crate::directives::macro_directive::MacroDirective;
55pub use crate::directives::module_directive::ModuleDirective;
56pub use crate::directives::struct_directive::StructDirective;
57pub use crate::directives::trait_directive::TraitDirective;
58pub use crate::directives::type_directive::TypeDirective;
59pub use crate::directives::use_directive::UseDirective;
60pub use crate::directives::variable_directive::VariableDirective;
61use crate::formats::{MdDirective, RstDirective};
62use crate::utils::SourceCodeFile;
63
64/// The Sphinx directives that are implemented by the Rust domain.
65#[derive(Clone, Debug)]
66pub(crate) enum Directive {
67    Crate(CrateDirective),
68    Enum(EnumDirective),
69    Executable(ExecutableDirective),
70    Function(FunctionDirective),
71    Impl(ImplDirective),
72    Macro(MacroDirective),
73    Module(ModuleDirective),
74    Struct(StructDirective),
75    Trait(TraitDirective),
76    Type(TypeDirective),
77    Use(UseDirective),
78    Variable(VariableDirective),
79}
80
81impl Directive {
82    fn name(&self) -> &str {
83        match self {
84            Directive::Crate(c) => &c.name,
85            Directive::Enum(e) => &e.name,
86            Directive::Executable(e) => &e.0.name,
87            Directive::Function(f) => &f.name,
88            Directive::Impl(i) => &i.name,
89            Directive::Macro(m) => &m.name,
90            Directive::Module(m) => &m.name,
91            Directive::Struct(s) => &s.name,
92            Directive::Trait(t) => &t.name,
93            Directive::Type(t) => &t.name,
94            Directive::Use(_) => {
95                unreachable!("name is used for sorting, which is not done for UseDirective")
96            }
97            Directive::Variable(v) => &v.name,
98        }
99    }
100
101    /// Change the parent of the directive.
102    fn change_parent(&mut self, new_parent: &str) {
103        match self {
104            Directive::Crate(_) => {
105                unreachable!("Crate directive shouldn't have parent")
106            }
107            Directive::Enum(e) => e.change_parent(new_parent),
108            Directive::Executable(_) => {
109                unreachable!("Executable directive shouldn't have parent")
110            }
111            Directive::Function(f) => f.change_parent(new_parent),
112            Directive::Impl(i) => i.change_parent(new_parent),
113            Directive::Macro(m) => m.change_parent(new_parent),
114            Directive::Module(m) => m.change_parent(new_parent),
115            Directive::Struct(s) => s.change_parent(new_parent),
116            Directive::Trait(t) => t.change_parent(new_parent),
117            Directive::Type(t) => t.change_parent(new_parent),
118            Directive::Use(_) => {}
119            Directive::Variable(v) => v.change_parent(new_parent),
120        }
121    }
122
123    /// Get the visibility of the directive.
124    fn directive_visibility(&self) -> &DirectiveVisibility {
125        match self {
126            Directive::Crate(_) => &DirectiveVisibility::Pub,
127            Directive::Enum(e) => e.directive_visibility(),
128            Directive::Executable(_) => &DirectiveVisibility::Pub,
129            Directive::Function(f) => f.directive_visibility(),
130            Directive::Impl(i) => i.directive_visibility(),
131            Directive::Macro(m) => m.directive_visibility(),
132            Directive::Module(m) => m.directive_visibility(),
133            Directive::Struct(s) => s.directive_visibility(),
134            Directive::Trait(t) => t.directive_visibility(),
135            Directive::Type(t) => t.directive_visibility(),
136            Directive::Use(u) => u.directive_visibility(),
137            Directive::Variable(v) => v.directive_visibility(),
138        }
139    }
140
141    /// Add the content to the directive.
142    ///
143    /// The content is appended to any existing content.
144    fn add_content<I: IntoIterator<Item = String>>(&mut self, content: I) {
145        match self {
146            Directive::Crate(d) => {
147                d.content.push(String::new());
148                d.content.extend(content);
149                d.content.push(String::new())
150            }
151            Directive::Enum(d) => {
152                d.content.push(String::new());
153                d.content.extend(content);
154                d.content.push(String::new())
155            }
156            Directive::Executable(d) => {
157                d.0.content.push(String::new());
158                d.0.content.extend(content);
159                d.0.content.push(String::new())
160            }
161            Directive::Function(d) => {
162                d.content.push(String::new());
163                d.content.extend(content);
164                d.content.push(String::new())
165            }
166            Directive::Impl(d) => {
167                d.content.push(String::new());
168                d.content.extend(content);
169                d.content.push(String::new())
170            }
171            Directive::Macro(d) => {
172                d.content.push(String::new());
173                d.content.extend(content);
174                d.content.push(String::new())
175            }
176            Directive::Module(d) => {
177                d.content.push(String::new());
178                d.content.extend(content);
179                d.content.push(String::new())
180            }
181            Directive::Struct(d) => {
182                d.content.push(String::new());
183                d.content.extend(content);
184                d.content.push(String::new())
185            }
186            Directive::Trait(d) => {
187                d.content.push(String::new());
188                d.content.extend(content);
189                d.content.push(String::new())
190            }
191            Directive::Type(d) => {
192                d.content.push(String::new());
193                d.content.extend(content);
194                d.content.push(String::new())
195            }
196            Directive::Use(d) => {
197                d.content.push(String::new());
198                d.content.extend(content);
199                d.content.push(String::new())
200            }
201            Directive::Variable(d) => {
202                d.content.push(String::new());
203                d.content.extend(content);
204                d.content.push(String::new())
205            }
206        }
207    }
208
209    /// Create the appropriate directive from the provided ``syn::Item``
210    ///
211    /// Args:
212    ///     :parent_path: The parent path of the item.
213    ///     :item: The item to parse into a directive.
214    ///
215    /// Returns:
216    ///     An option a :rust:enum:`Directive` variant.
217    fn from_item(
218        parent_path: &str,
219        item: &Item,
220        inherited_visibility: &Option<&Visibility>,
221    ) -> Option<Directive> {
222        match item {
223            Item::Const(c) => Some(VariableDirective::from_const(parent_path, c)),
224            Item::Enum(e) => Some(EnumDirective::from_item(parent_path, e)),
225            Item::ExternCrate(_) => None,
226            Item::Fn(f) => Some(FunctionDirective::from_item(parent_path, f)),
227            Item::ForeignMod(_) => panic!("ForeignMod items cannot be converted to a single item"),
228            Item::Impl(i) => Some(Directive::Impl(ImplDirective::from_item(
229                parent_path,
230                i,
231                inherited_visibility,
232            ))),
233            Item::Macro(m) => MacroDirective::from_item(parent_path, m),
234            Item::Mod(_) => panic!("Module directives must be created with a source code file"),
235            Item::Static(s) => Some(VariableDirective::from_static(parent_path, s)),
236            Item::Struct(s) => Some(StructDirective::from_item(parent_path, s)),
237            Item::Trait(t) => Some(TraitDirective::from_item(parent_path, t)),
238            Item::TraitAlias(t) => Some(TraitDirective::from_alias(parent_path, t)),
239            Item::Type(t) => Some(TypeDirective::from_item(parent_path, t)),
240            Item::Union(u) => Some(StructDirective::from_union(parent_path, u)),
241            Item::Use(u) => Some(UseDirective::from_item_as_directive(parent_path, u)),
242            Item::Verbatim(_) => None,
243            i => panic!("Unexpected item: {:?}", i),
244        }
245    }
246
247    /// Create the appropriate directive from the provided ``syn::ImplItem``
248    ///
249    /// Args:
250    ///     :parent_path: The path of the impl block which defines the item.
251    ///     :item: The impl item to parse into a directive.
252    ///
253    /// Returns:
254    ///     An option a :rust:enum:`Directive` variant.
255    fn from_impl_item(
256        parent_path: &str,
257        item: &ImplItem,
258        inherited_visibility: &Option<&Visibility>,
259    ) -> Option<Directive> {
260        match item {
261            ImplItem::Const(c) => Some(VariableDirective::from_impl_const(
262                parent_path,
263                c,
264                inherited_visibility,
265            )),
266            ImplItem::Fn(f) => Some(FunctionDirective::from_impl_item(
267                parent_path,
268                f,
269                inherited_visibility,
270            )),
271            ImplItem::Type(t) => Some(TypeDirective::from_impl_item(
272                parent_path,
273                t,
274                inherited_visibility,
275            )),
276            ImplItem::Macro(_) | ImplItem::Verbatim(_) => None,
277            i => panic!("Unexpected impl item: {:?}", i),
278        }
279    }
280
281    /// Create the appropriate directives from the provided ``syn::ImplItem``
282    /// iterator.
283    ///
284    /// Args:
285    ///     :parent_path: The path of the impl block which defines the items.
286    ///     :items: The impl items to parse into a directive.
287    ///
288    /// Returns:
289    ///     An vec of :rust:enum:`Directive` variants.
290    fn from_impl_items<'a, T: Iterator<Item = &'a ImplItem>>(
291        parent_path: &str,
292        items: T,
293        inherited_visibility: &Option<&Visibility>,
294    ) -> Vec<Directive> {
295        items
296            .filter_map(|i| Self::from_impl_item(parent_path, i, inherited_visibility))
297            .collect()
298    }
299
300    /// Create the appropriate directive from the provided ``syn::TraitItem``
301    ///
302    /// Args:
303    ///     :parent_path: The path of the trait which defines the items.
304    ///     :item: The trait item to parse into a directive.
305    ///
306    /// Returns:
307    ///     An option a :rust:enum:`Directive` variant.
308    fn from_trait_item(
309        parent_path: &str,
310        item: &TraitItem,
311        inherited_visibility: &Option<&Visibility>,
312    ) -> Option<Directive> {
313        match item {
314            TraitItem::Const(c) => Some(VariableDirective::from_trait_const(
315                parent_path,
316                c,
317                inherited_visibility,
318            )),
319            TraitItem::Fn(f) => Some(FunctionDirective::from_trait_item(
320                parent_path,
321                f,
322                inherited_visibility,
323            )),
324            TraitItem::Type(t) => Some(TypeDirective::from_trait_item(
325                parent_path,
326                t,
327                inherited_visibility,
328            )),
329            TraitItem::Macro(_) | TraitItem::Verbatim(_) => None,
330            i => panic!("Unexpected trait item: {:?}", i),
331        }
332    }
333
334    /// Create the appropriate directives from the provided ``syn::TraitItem``
335    /// iterator.
336    ///
337    /// Args:
338    ///     :parent_path: The path of the module which defines the items.
339    ///     :items: The trait items to parse into a directive.
340    ///
341    /// Returns:
342    ///     An vec of :rust:enum:`Directive` variants.
343    fn from_trait_items<'a, T: Iterator<Item = &'a TraitItem>>(
344        parent_path: &str,
345        items: T,
346        inherited_visibility: &Option<&Visibility>,
347    ) -> Vec<Directive> {
348        items
349            .filter_map(|i| Self::from_trait_item(parent_path, i, inherited_visibility))
350            .collect()
351    }
352
353    /// Create the appropriate directive from the provided ``syn::ForeignItem``
354    ///
355    /// Args:
356    ///     :parent_path: The path of the module which defines the items.
357    ///     :item: The foreign item to parse into a directive.
358    ///
359    /// Returns:
360    ///     An option a :rust:enum:`Directive` variant.
361    fn from_extern_item(parent_path: &str, item: &ForeignItem) -> Option<Directive> {
362        match item {
363            ForeignItem::Fn(f) => Some(FunctionDirective::from_extern(parent_path, f)),
364            ForeignItem::Static(s) => Some(VariableDirective::from_extern_static(parent_path, s)),
365            ForeignItem::Type(t) => Some(TypeDirective::from_extern(parent_path, t)),
366            _ => None,
367        }
368    }
369
370    /// Create the appropriate directives from the provided ``syn::ForeignItem``
371    /// iterator.
372    ///
373    /// Args:
374    ///     :parent_path: The path of the trait which defines the items.
375    ///     :items: The foreign items to parse into a directive.
376    ///
377    /// Returns:
378    ///     An vec of :rust:enum:`Directive` variants.
379    fn from_extern_items<'a, T: Iterator<Item = &'a ForeignItem>>(
380        parent_path: &str,
381        items: T,
382    ) -> Vec<Directive> {
383        items
384            .filter_map(|i| Self::from_extern_item(parent_path, i))
385            .collect()
386    }
387}
388
389impl RstDirective for Directive {
390    fn get_rst_text(self, level: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
391        match self {
392            Directive::Crate(c) => c.get_rst_text(level, max_visibility),
393            Directive::Enum(e) => e.get_rst_text(level, max_visibility),
394            Directive::Executable(e) => e.get_rst_text(level, max_visibility),
395            Directive::Function(f) => f.get_rst_text(level, max_visibility),
396            Directive::Impl(i) => i.get_rst_text(level, max_visibility),
397            Directive::Macro(m) => m.get_rst_text(level, max_visibility),
398            Directive::Module(m) => m.get_rst_text(level, max_visibility),
399            Directive::Struct(s) => s.get_rst_text(level, max_visibility),
400            Directive::Trait(t) => t.get_rst_text(level, max_visibility),
401            Directive::Type(t) => t.get_rst_text(level, max_visibility),
402            Directive::Use(u) => u.get_rst_text(level, max_visibility),
403            Directive::Variable(v) => v.get_rst_text(level, max_visibility),
404        }
405    }
406}
407
408impl MdDirective for Directive {
409    fn get_md_text(self, fence_size: usize, max_visibility: &DirectiveVisibility) -> Vec<String> {
410        match self {
411            Directive::Crate(c) => c.get_md_text(fence_size, max_visibility),
412            Directive::Enum(e) => e.get_md_text(fence_size, max_visibility),
413            Directive::Executable(e) => e.get_md_text(fence_size, max_visibility),
414            Directive::Function(f) => f.get_md_text(fence_size, max_visibility),
415            Directive::Impl(i) => i.get_md_text(fence_size, max_visibility),
416            Directive::Macro(m) => m.get_md_text(fence_size, max_visibility),
417            Directive::Module(m) => m.get_md_text(fence_size, max_visibility),
418            Directive::Struct(s) => s.get_md_text(fence_size, max_visibility),
419            Directive::Trait(t) => t.get_md_text(fence_size, max_visibility),
420            Directive::Type(t) => t.get_md_text(fence_size, max_visibility),
421            Directive::Use(u) => u.get_md_text(fence_size, max_visibility),
422            Directive::Variable(v) => v.get_md_text(fence_size, max_visibility),
423        }
424    }
425
426    fn fence_size(&self) -> usize {
427        match self {
428            Directive::Crate(c) => c.fence_size(),
429            Directive::Enum(e) => e.fence_size(),
430            Directive::Executable(e) => e.fence_size(),
431            Directive::Function(f) => f.fence_size(),
432            Directive::Impl(i) => i.fence_size(),
433            Directive::Macro(m) => m.fence_size(),
434            Directive::Module(m) => m.fence_size(),
435            Directive::Struct(s) => s.fence_size(),
436            Directive::Trait(t) => t.fence_size(),
437            Directive::Type(t) => t.fence_size(),
438            Directive::Use(u) => u.fence_size(),
439            Directive::Variable(v) => v.fence_size(),
440        }
441    }
442}
443
444/// Extract the docstring from the attrs of an item.
445///
446/// Args:
447///     :attrs: ``syn::attr::Attribute`` vec.
448///
449/// Returns:
450///     A vec of strings, where each string is a line of a documentation
451///     comment. If there are no documentation comments, an empty vec is
452///     returned.
453pub(crate) fn extract_doc_from_attrs(attrs: &Vec<Attribute>) -> Vec<String> {
454    let mut content = Vec::new();
455    for attr in attrs {
456        if attr.path().segments.is_empty() || attr.path().segments[0].ident != "doc" {
457            continue;
458        }
459
460        if let Expr::Lit(e) = &attr.meta.require_name_value().unwrap().value {
461            if let Lit::Str(d) = &e.lit {
462                let line = d.value();
463                content.push(line.strip_prefix(' ').unwrap_or(&line).to_string());
464            }
465        }
466    }
467    content
468}
469
470/// Macro to sort and push items within a vec.
471macro_rules! push_sorted {
472    ($sorted:expr, $items:expr, $name:expr) => {{
473        if !$items.is_empty() {
474            $items.sort_by(|a, b| a.name().cmp(b.name()));
475            $sorted.push(($name, $items));
476        }
477    }};
478}
479
480/// Named type for the output of :rust:fn:`order_items`.
481type ItemSections = Vec<(&'static str, Vec<Directive>)>;
482
483/// Order the items for documentation
484///
485/// The items are ordered using the following rules:
486///
487/// 1. If the item is a module without content, it is removed and a link to the
488///    module is added to the ``toctree``. If there are no such module, the
489///    ``toctree`` isn't added.
490/// 2. Each directive is then separated by type and ordered alphabetically
491///    except for ``impl`` directives.
492/// 3. All ``impl`` blocks associated with a struct or enum are ordered after
493///    it, starting with the associated ``impl`` block, followed by trait
494///    ``impl`` blocks in alphabetical order.
495///
496/// It uses the :rust:any:`push_sorted!()` macro.
497///
498/// Returns:
499///    A vec of section names with their directives.
500fn order_items(items: Vec<Directive>) -> ItemSections {
501    let mut enums = vec![];
502    let mut fns = vec![];
503    let mut impls = vec![];
504    let mut macros = vec![];
505    let mut structs = vec![];
506    let mut traits = vec![];
507    let mut types = vec![];
508    let mut vars = vec![];
509
510    for item in items {
511        match item {
512            Directive::Crate(_) => {
513                unreachable!("Unexpected crate directive as an item")
514            }
515            Directive::Enum(e) => enums.push(Directive::Enum(e)),
516            Directive::Executable(_) => {
517                unreachable!("Unexpected executable directive as an item")
518            }
519            Directive::Function(f) => fns.push(Directive::Function(f)),
520            Directive::Impl(i) => impls.push(Directive::Impl(i)),
521            Directive::Macro(m) => macros.push(Directive::Macro(m)),
522            Directive::Module(_) => unreachable!("Unexpected module directive as item"),
523            Directive::Struct(s) => structs.push(Directive::Struct(s)),
524            Directive::Trait(t) => traits.push(Directive::Trait(t)),
525            Directive::Type(t) => types.push(Directive::Type(t)),
526            Directive::Use(_) => unreachable!("Unexpected use directive as item"),
527            Directive::Variable(v) => vars.push(Directive::Variable(v)),
528        }
529    }
530
531    impls.sort_by(|a, b| a.name().cmp(b.name()));
532
533    let mut sorted = Vec::new();
534    push_sorted!(sorted, types, "Types");
535    push_sorted!(sorted, vars, "Variables");
536    push_sorted!(sorted, macros, "Macros");
537    push_sorted!(sorted, fns, "Functions");
538
539    push_sorted!(sorted, traits, "Traits");
540    push_sorted!(sorted, enums, "Enums");
541    push_sorted!(sorted, structs, "Structs and Unions");
542    push_sorted!(sorted, impls, "Impls");
543
544    sorted
545}
546
547#[derive(Clone, Debug)]
548pub(crate) struct FileDirectives {
549    /// The directives for the modules defined in the file.
550    pub(crate) modules: Vec<ModuleDirective>,
551    /// The directives for the impls defined in the file.
552    pub(crate) impls: Vec<ImplDirective>,
553    /// The directives for the use statements in the file.
554    pub(crate) uses: Vec<UseDirective>,
555    /// The directives for all other items in the file.
556    /// This will never contain a module, impl or use directive.
557    pub(crate) items: Vec<Directive>,
558}
559
560impl FileDirectives {
561    /// Create new file directives from the AST of a file.
562    ///
563    /// Args:
564    ///     :ast_items: A list of items parsed by syn.
565    ///     :module_parent: The parent source code file to find
566    ///        modules under.
567    fn from_ast_items(ast_items: &Vec<Item>, module_parent: &SourceCodeFile) -> Self {
568        let mut modules = vec![];
569        let mut impls = vec![];
570        let mut uses = vec![
571            UseDirective::for_path(&module_parent.item, "self"),
572            UseDirective::for_path(module_parent.crate_name(), "crate"),
573        ];
574        let mut items = vec![];
575
576        for item in ast_items {
577            match item {
578                Item::Mod(m) => {
579                    if let Some(md) = ModuleDirective::from_item(module_parent, m) {
580                        modules.push(md);
581                    }
582                }
583                Item::Use(u) => {
584                    uses.push(UseDirective::from_item(&module_parent.item, u));
585                }
586                Item::Impl(i) => {
587                    impls.push(ImplDirective::from_item(&module_parent.item, i, &None));
588                }
589                Item::ForeignMod(f) => {
590                    items.extend(Directive::from_extern_items(
591                        &module_parent.item,
592                        f.items.iter(),
593                    ));
594                }
595                _ => {
596                    if let Some(i) = Directive::from_item(&module_parent.item, item, &None) {
597                        items.push(i);
598                    }
599                }
600            }
601        }
602
603        // Resolve any use paths that are relative to the file.
604        for use_ in &mut uses {
605            use_.resolve_relative_paths(&modules);
606        }
607
608        // Resolve the self_ty and trait_ for the impls.
609        // If either self_ty or trait_ is defined in the module itself,
610        // they will not resolve. Also, items from the preamble will not
611        // resolve. In this case, the resolved names are left as is. It
612        // doesn't really matter here since the check for which item owns the
613        // impl will only resolve when the name matches entirely.
614        for impl_ in &mut impls {
615            for use_ in &uses {
616                if let Some(path) = use_.find(&impl_.self_ty) {
617                    impl_.resolved_self_ty = path.clone();
618                }
619                else if let Some(trait_) = &impl_.trait_ {
620                    if let Some(path) =
621                        use_.find(trait_.strip_prefix('!').unwrap_or_else(|| trait_))
622                    {
623                        impl_.resolved_trait = Some(path.clone());
624                    }
625                }
626            }
627        }
628
629        FileDirectives {
630            modules,
631            impls,
632            uses,
633            items,
634        }
635    }
636
637    fn claim_impls(&mut self, parent_name: &str, impls: Vec<ImplDirective>) -> Vec<ImplDirective> {
638        let mut remaining = vec![];
639
640        'impl_loop: for impl_ in impls {
641            // Check for enums and structs first
642            for item in &mut self.items {
643                match item {
644                    Directive::Enum(e) if impl_.for_item(&e.name) => {
645                        e.add_impl(impl_);
646                        continue 'impl_loop;
647                    }
648                    Directive::Struct(s) if impl_.for_item(&s.name) => {
649                        s.add_impl(impl_);
650                        continue 'impl_loop;
651                    }
652                    _ => {}
653                }
654            }
655            // Check for trait impls where self_ty is not in crate or a generic.
656            for item in &mut self.items {
657                match item {
658                    Directive::Trait(t) if impl_.for_trait(&t.name, parent_name) => {
659                        t.add_impl(impl_);
660                        continue 'impl_loop;
661                    }
662                    _ => {}
663                }
664            }
665            remaining.push(impl_)
666        }
667
668        // Recurse into submodules
669        for module in &mut self.modules {
670            remaining = module.claim_impls(remaining);
671        }
672        remaining
673    }
674}