From 11e0f9f10c566cb494cb748ea0a7216bab6f0cd6 Mon Sep 17 00:00:00 2001 From: Vincent Esche Date: Sat, 7 Oct 2023 01:10:29 +0200 Subject: [PATCH] Recognize dependencies from types' fields, etc --- src/graph/builder.rs | 330 ++++++++++++------ src/graph/util.rs | 18 + .../generate_graph__fields__enum_fields.snap | 9 + ...generate_graph__fields__struct_fields.snap | 9 + .../generate_graph__fields__tuple_fields.snap | 8 + .../generate_graph__fields__union_fields.snap | 9 + 6 files changed, 274 insertions(+), 109 deletions(-) diff --git a/src/graph/builder.rs b/src/graph/builder.rs index 497add62..137c6ffa 100644 --- a/src/graph/builder.rs +++ b/src/graph/builder.rs @@ -7,7 +7,6 @@ use std::{ path::{Path, PathBuf}, }; -use hir::{HasCrate, HirDisplay, ModuleDef}; use log::trace; use petgraph::graph::{EdgeIndex, NodeIndex}; use ra_ap_hir::{self as hir, Crate, ModuleSource}; @@ -21,11 +20,10 @@ use crate::graph::{ visibility::NodeVisibility, Node, }, + orphans::add_orphan_nodes_to, util, Graph, }; -use super::orphans::add_orphan_nodes_to; - #[derive(Clone, PartialEq, Eq, Debug)] pub struct Options { pub orphans: bool, @@ -46,8 +44,6 @@ pub struct Builder<'a> { graph: Graph, nodes: HashMap, edges: HashMap<(NodeIndex, EdgeKind, NodeIndex), EdgeIndex>, - stack: Vec, - pending: HashSet, } impl<'a> Builder<'a> { @@ -55,8 +51,6 @@ impl<'a> Builder<'a> { let graph = Graph::default(); let nodes = HashMap::default(); let edges = HashMap::default(); - let stack = Vec::default(); - let pending = HashSet::default(); Self { options, @@ -66,8 +60,6 @@ impl<'a> Builder<'a> { graph, nodes, edges, - stack, - pending, } } @@ -83,155 +75,291 @@ impl<'a> Builder<'a> { fn process_crate(&mut self, krate: Crate) -> Option { let module = krate.root_module(); - self.process_module(module, true) + + self.process_moduledef(module.into()) } - fn process_moduledef( - &mut self, - moduledef_hir: hir::ModuleDef, - is_recursive: bool, - ) -> Option { - match moduledef_hir { - hir::ModuleDef::Module(module_hir) => self.process_module(module_hir, is_recursive), + fn process_moduledef(&mut self, moduledef_hir: hir::ModuleDef) -> Option { + let mut dependencies: HashSet<_> = HashSet::default(); + + let mut push_dependencies = |moduledef_hir| { + dependencies.insert(moduledef_hir); + }; + + let node_idx = match moduledef_hir { + hir::ModuleDef::Module(module_hir) => { + self.process_module(module_hir, &mut push_dependencies) + } hir::ModuleDef::Function(function_hir) => { - self.process_function(function_hir, is_recursive) + self.process_function(function_hir, &mut push_dependencies) + } + hir::ModuleDef::Adt(adt_hir) => self.process_adt(adt_hir, &mut push_dependencies), + hir::ModuleDef::Variant(variant_hir) => { + self.process_variant(variant_hir, &mut push_dependencies) + } + hir::ModuleDef::Const(const_hir) => { + self.process_const(const_hir, &mut push_dependencies) + } + hir::ModuleDef::Static(static_hir) => { + self.process_static(static_hir, &mut push_dependencies) + } + hir::ModuleDef::Trait(trait_hir) => { + self.process_trait(trait_hir, &mut push_dependencies) } - hir::ModuleDef::Adt(adt_hir) => self.process_adt(adt_hir, is_recursive), - hir::ModuleDef::Variant(variant_hir) => self.process_variant(variant_hir, is_recursive), - hir::ModuleDef::Const(const_hir) => self.process_const(const_hir, is_recursive), - hir::ModuleDef::Static(static_hir) => self.process_static(static_hir, is_recursive), - hir::ModuleDef::Trait(trait_hir) => self.process_trait(trait_hir, is_recursive), hir::ModuleDef::TraitAlias(trait_alias_hir) => { - self.process_trait_alias(trait_alias_hir, is_recursive) + self.process_trait_alias(trait_alias_hir, &mut push_dependencies) } hir::ModuleDef::TypeAlias(type_alias_hir) => { - self.process_type_alias(type_alias_hir, is_recursive) + self.process_type_alias(type_alias_hir, &mut push_dependencies) } hir::ModuleDef::BuiltinType(builtin_type_hir) => { - self.process_builtin_type(builtin_type_hir, is_recursive) + self.process_builtin_type(builtin_type_hir, &mut push_dependencies) + } + hir::ModuleDef::Macro(macro_hir) => { + self.process_macro(macro_hir, &mut push_dependencies) } - hir::ModuleDef::Macro(macro_hir) => self.process_macro(macro_hir, is_recursive), + }; + + if let Some(node_idx) = node_idx { + self.add_dependencies(node_idx, dependencies); } + + node_idx } - fn process_module(&mut self, module_hir: hir::Module, is_recursive: bool) -> Option { - let module_idx = match self.add_node(module_hir.into()) { - Some(owned_idx) => owned_idx, - None => return None, - }; + fn process_module( + &mut self, + module_hir: hir::Module, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), + ) -> Option { + let node_idx = self.add_node(module_hir.into()); + + if let Some(node_idx) = node_idx { + // Process sub-items: + for declaration in module_hir.declarations(self.db) { + let Some(declaration_idx) = self.process_moduledef(declaration) else { + continue; + }; + + let edge = Edge { + kind: EdgeKind::Owns, + }; - if !is_recursive { - return Some(module_idx); + self.add_edge(node_idx, declaration_idx, edge); + } + + // Add orphan nodes: + if self.options.orphans { + add_orphan_nodes_to(&mut self.graph, node_idx); + } } - for declaration in module_hir.declarations(self.db) { - let Some(declaration_idx) = self.process_moduledef(declaration, is_recursive) else { + for (_name, scope_hir) in module_hir.scope(self.db, None) { + let hir::ScopeDef::ModuleDef(scope_module_hir) = scope_hir else { + // Skip everything but module-defs: continue; }; - let edge = Edge { - kind: EdgeKind::Owns, - }; - - self.add_edge(module_idx, declaration_idx, edge); - } + // Check if definition is a child of `module`: + if scope_module_hir.module(self.db) == Some(module_hir) { + // Is a child, omit it: + continue; + } - if self.options.orphans { - add_orphan_nodes_to(&mut self.graph, module_idx); + dependencies_callback(scope_module_hir); } - self.add_dependencies(module_idx, self.dependencies_of_module(module_hir)); - - Some(module_idx) + node_idx } fn process_function( &mut self, function_hir: hir::Function, - _is_recursive: bool, + _dependencies_callback: &mut dyn FnMut(hir::ModuleDef), ) -> Option { - self.add_node(hir::ModuleDef::Function(function_hir)) + let node_idx = self.add_node(hir::ModuleDef::Function(function_hir)); + + // TODO: scan function for dependencies + + #[allow(clippy::let_and_return)] + node_idx } - fn process_adt(&mut self, adt_hir: hir::Adt, is_recursive: bool) -> Option { + fn process_adt( + &mut self, + adt_hir: hir::Adt, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), + ) -> Option { match adt_hir { - hir::Adt::Struct(struct_hir) => self.process_struct(struct_hir, is_recursive), - hir::Adt::Enum(enum_hir) => self.process_enum(enum_hir, is_recursive), - hir::Adt::Union(union_hir) => self.process_union(union_hir, is_recursive), + hir::Adt::Struct(struct_hir) => self.process_struct(struct_hir, dependencies_callback), + hir::Adt::Enum(enum_hir) => self.process_enum(enum_hir, dependencies_callback), + hir::Adt::Union(union_hir) => self.process_union(union_hir, dependencies_callback), } } fn process_struct( &mut self, struct_hir: hir::Struct, - _is_recursive: bool, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), ) -> Option { - self.add_node(hir::ModuleDef::Adt(hir::Adt::Struct(struct_hir))) + let node_idx = self.add_node(hir::ModuleDef::Adt(hir::Adt::Struct(struct_hir))); + + for field_hir in struct_hir.fields(self.db) { + util::walk_and_push_ty( + field_hir.ty(self.db).strip_references(), + self.db, + dependencies_callback, + ); + } + + node_idx } - fn process_union(&mut self, union_hir: hir::Union, _is_recursive: bool) -> Option { - self.add_node(hir::ModuleDef::Adt(hir::Adt::Union(union_hir))) + fn process_enum( + &mut self, + enum_hir: hir::Enum, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), + ) -> Option { + let node_idx = self.add_node(hir::ModuleDef::Adt(hir::Adt::Enum(enum_hir))); + + for variant_hir in enum_hir.variants(self.db) { + for field_hir in variant_hir.fields(self.db) { + util::walk_and_push_ty( + field_hir.ty(self.db).strip_references(), + self.db, + dependencies_callback, + ); + } + } + + node_idx } - fn process_enum(&mut self, enum_hir: hir::Enum, _is_recursive: bool) -> Option { - self.add_node(hir::ModuleDef::Adt(hir::Adt::Enum(enum_hir))) + fn process_union( + &mut self, + union_hir: hir::Union, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), + ) -> Option { + let node_idx = self.add_node(hir::ModuleDef::Adt(hir::Adt::Union(union_hir))); + + for field_hir in union_hir.fields(self.db) { + util::walk_and_push_ty( + field_hir.ty(self.db).strip_references(), + self.db, + dependencies_callback, + ); + } + + node_idx } fn process_variant( &mut self, - _variant_hir: hir::Variant, - _is_recursive: bool, + variant_hir: hir::Variant, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), ) -> Option { - None + let node_idx = None; + + for field_hir in variant_hir.fields(self.db) { + util::walk_and_push_ty(field_hir.ty(self.db), self.db, dependencies_callback); + } + + node_idx } - fn process_const(&mut self, _const_hir: hir::Const, _is_recursive: bool) -> Option { - None + fn process_const( + &mut self, + const_hir: hir::Const, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), + ) -> Option { + let node_idx = None; + + util::walk_and_push_ty(const_hir.ty(self.db), self.db, dependencies_callback); + + node_idx } fn process_static( &mut self, static_hir: hir::Static, - _is_recursive: bool, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), ) -> Option { - self.add_node(hir::ModuleDef::Static(static_hir)) + let node_idx = None; + + util::walk_and_push_ty(static_hir.ty(self.db), self.db, dependencies_callback); + + node_idx } - fn process_trait(&mut self, trait_hir: hir::Trait, _is_recursive: bool) -> Option { - self.add_node(hir::ModuleDef::Trait(trait_hir)) + fn process_trait( + &mut self, + trait_hir: hir::Trait, + _dependencies_callback: &mut dyn FnMut(hir::ModuleDef), + ) -> Option { + let node_idx = self.add_node(hir::ModuleDef::Trait(trait_hir)); + + // TODO: walk types? + + #[allow(clippy::let_and_return)] + node_idx } fn process_trait_alias( &mut self, trait_alias_hir: hir::TraitAlias, - _is_recursive: bool, + _dependencies_callback: &mut dyn FnMut(hir::ModuleDef), ) -> Option { - self.add_node(hir::ModuleDef::TraitAlias(trait_alias_hir)) + let node_idx = self.add_node(hir::ModuleDef::TraitAlias(trait_alias_hir)); + + // TODO: walk types? + + #[allow(clippy::let_and_return)] + node_idx } fn process_type_alias( &mut self, type_alias_hir: hir::TypeAlias, - _is_recursive: bool, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), ) -> Option { - self.add_node(hir::ModuleDef::TypeAlias(type_alias_hir)) + let node_idx = self.add_node(hir::ModuleDef::TypeAlias(type_alias_hir)); + + util::walk_and_push_ty(type_alias_hir.ty(self.db), self.db, dependencies_callback); + + node_idx } fn process_builtin_type( &mut self, builtin_type_hir: hir::BuiltinType, - _is_recursive: bool, + dependencies_callback: &mut dyn FnMut(hir::ModuleDef), ) -> Option { - self.add_node(hir::ModuleDef::BuiltinType(builtin_type_hir)) + let node_idx = self.add_node(hir::ModuleDef::BuiltinType(builtin_type_hir)); + + util::walk_and_push_ty(builtin_type_hir.ty(self.db), self.db, dependencies_callback); + + node_idx } - fn process_macro(&mut self, _macro_hir: hir::Macro, _is_recursive: bool) -> Option { - None + fn process_macro( + &mut self, + _macro_hir: hir::Macro, + _dependencies_callback: &mut dyn FnMut(hir::ModuleDef), + ) -> Option { + let node_idx = None; + + // TODO: walk types? + + #[allow(clippy::let_and_return)] + node_idx } - fn add_dependencies(&mut self, depender_idx: NodeIndex, dependencies: Vec) { + fn add_dependencies(&mut self, depender_idx: NodeIndex, dependencies: I) + where + I: IntoIterator, + { for dependency_hir in dependencies { - let Some(dependency_hir) = self.process_moduledef(dependency_hir, false) else { + let Some(dependency_hir) = self.add_node(dependency_hir) else { continue; }; @@ -243,27 +371,6 @@ impl<'a> Builder<'a> { } } - fn dependencies_of_module(&self, module_hir: hir::Module) -> Vec { - module_hir - .scope(self.db, None) - .into_iter() - .filter_map(move |(_name, scope_hir)| { - let hir::ScopeDef::ModuleDef(scope_module_hir) = scope_hir else { - // Skip everything but module-defs: - return None; - }; - - // Check if definition is a child of `module`: - if scope_module_hir.module(self.db) == Some(module_hir) { - // Is a child, omit it: - return None; - } - - Some(scope_module_hir) - }) - .collect() - } - fn add_node(&mut self, moduledef_hir: hir::ModuleDef) -> Option { let node_id = util::path(moduledef_hir, self.db); @@ -290,7 +397,16 @@ impl<'a> Builder<'a> { } } - fn add_edge(&mut self, source_idx: NodeIndex, target_idx: NodeIndex, edge: Edge) -> EdgeIndex { + fn add_edge( + &mut self, + source_idx: NodeIndex, + target_idx: NodeIndex, + edge: Edge, + ) -> Option { + if source_idx == target_idx { + return None; + } + let edge_id = (source_idx, edge.kind, target_idx); // trace!( @@ -301,7 +417,7 @@ impl<'a> Builder<'a> { // ); // Check if we already added an equivalent edge: - match self.edges.get(&edge_id) { + let edge_idx = match self.edges.get(&edge_id) { Some(edge_idx) => { // If we did indeed already process it, then retrieve its index: *edge_idx @@ -313,7 +429,9 @@ impl<'a> Builder<'a> { edge_idx } - } + }; + + Some(edge_idx) } fn node_weight(&self, moduledef_hir: hir::ModuleDef) -> Option { @@ -331,13 +449,7 @@ impl<'a> Builder<'a> { Some(s.to_owned()) } }) - .filter_map(|s| { - if s.is_empty() { - None - } else { - Some(s.to_owned()) - } - }) + .filter_map(|s| if s.is_empty() { None } else { Some(s) }) .collect(); let file_path = { diff --git a/src/graph/util.rs b/src/graph/util.rs index e357b2d8..0f9dedcd 100644 --- a/src/graph/util.rs +++ b/src/graph/util.rs @@ -59,6 +59,24 @@ where nodes_to_keep } +pub(super) fn walk_and_push_ty( + ty: hir::Type, + db: &RootDatabase, + visit: &mut dyn FnMut(hir::ModuleDef), +) { + ty.walk(db, |ty| { + if let Some(adt) = ty.as_adt() { + visit(adt.into()); + } else if let Some(trait_) = ty.as_dyn_trait() { + visit(trait_.into()); + } else if let Some(traits) = ty.as_impl_traits(db) { + traits.for_each(|it| visit(it.into())); + } else if let Some(trait_) = ty.as_associated_type_parent_trait(db) { + visit(trait_.into()); + } + }); +} + pub(crate) fn krate_name(krate: hir::Crate, db: &RootDatabase) -> String { // Obtain the crate's declaration name: let display_name = &krate.display_name(db).unwrap(); diff --git a/tests/snapshots/generate_graph__fields__enum_fields.snap b/tests/snapshots/generate_graph__fields__enum_fields.snap index 27675885..81b0e8bf 100644 --- a/tests/snapshots/generate_graph__fields__enum_fields.snap +++ b/tests/snapshots/generate_graph__fields__enum_fields.snap @@ -52,8 +52,17 @@ digraph { "enum_fields" -> "enum_fields::GenericTargetUnion" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "enum_fields" -> "enum_fields::TargetEnum" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "enum_fields" -> "enum_fields::TargetStruct" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "enum_fields" -> "enum_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge "enum_fields" -> "enum_fields::TargetTrait" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "enum_fields" -> "enum_fields::TargetUnion" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "enum_fields::Enum" -> "enum_fields::GenericTargetEnum" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "enum_fields::Enum" -> "enum_fields::GenericTargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "enum_fields::Enum" -> "enum_fields::GenericTargetUnion" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "enum_fields::Enum" -> "enum_fields::TargetEnum" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "enum_fields::Enum" -> "enum_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "enum_fields::Enum" -> "enum_fields::TargetTrait" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "enum_fields::Enum" -> "enum_fields::TargetUnion" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "enum_fields::TargetUnion" -> "enum_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge } diff --git a/tests/snapshots/generate_graph__fields__struct_fields.snap b/tests/snapshots/generate_graph__fields__struct_fields.snap index 905ffe04..b9b3f445 100644 --- a/tests/snapshots/generate_graph__fields__struct_fields.snap +++ b/tests/snapshots/generate_graph__fields__struct_fields.snap @@ -52,8 +52,17 @@ digraph { "struct_fields" -> "struct_fields::Struct" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "struct_fields" -> "struct_fields::TargetEnum" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "struct_fields" -> "struct_fields::TargetStruct" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "struct_fields" -> "struct_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge "struct_fields" -> "struct_fields::TargetTrait" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "struct_fields" -> "struct_fields::TargetUnion" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "struct_fields::Struct" -> "struct_fields::GenericTargetEnum" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "struct_fields::Struct" -> "struct_fields::GenericTargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "struct_fields::Struct" -> "struct_fields::GenericTargetUnion" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "struct_fields::Struct" -> "struct_fields::TargetEnum" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "struct_fields::Struct" -> "struct_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "struct_fields::Struct" -> "struct_fields::TargetTrait" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "struct_fields::Struct" -> "struct_fields::TargetUnion" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "struct_fields::TargetUnion" -> "struct_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge } diff --git a/tests/snapshots/generate_graph__fields__tuple_fields.snap b/tests/snapshots/generate_graph__fields__tuple_fields.snap index 2b92cac3..1d1cfbb5 100644 --- a/tests/snapshots/generate_graph__fields__tuple_fields.snap +++ b/tests/snapshots/generate_graph__fields__tuple_fields.snap @@ -47,13 +47,21 @@ digraph { "tuple_fields::TargetUnion" [label="pub(crate) union|tuple_fields::TargetUnion", fillcolor="#f8c04c"]; // "union" node "tuple_fields" -> "tuple_fields::DynTrait" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "tuple_fields" -> "tuple_fields::DynTrait" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge "tuple_fields" -> "tuple_fields::GenericTargetEnum" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "tuple_fields" -> "tuple_fields::GenericTargetEnum" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge "tuple_fields" -> "tuple_fields::GenericTargetStruct" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "tuple_fields" -> "tuple_fields::GenericTargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge "tuple_fields" -> "tuple_fields::GenericTargetUnion" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "tuple_fields" -> "tuple_fields::GenericTargetUnion" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge "tuple_fields" -> "tuple_fields::TargetEnum" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "tuple_fields" -> "tuple_fields::TargetEnum" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge "tuple_fields" -> "tuple_fields::TargetStruct" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "tuple_fields" -> "tuple_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge "tuple_fields" -> "tuple_fields::TargetTrait" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "tuple_fields" -> "tuple_fields::TargetUnion" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "tuple_fields" -> "tuple_fields::TargetUnion" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "tuple_fields::TargetUnion" -> "tuple_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge } diff --git a/tests/snapshots/generate_graph__fields__union_fields.snap b/tests/snapshots/generate_graph__fields__union_fields.snap index cdac1e74..d3bdc226 100644 --- a/tests/snapshots/generate_graph__fields__union_fields.snap +++ b/tests/snapshots/generate_graph__fields__union_fields.snap @@ -51,9 +51,18 @@ digraph { "union_fields" -> "union_fields::GenericTargetUnion" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "union_fields" -> "union_fields::TargetEnum" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "union_fields" -> "union_fields::TargetStruct" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "union_fields" -> "union_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge "union_fields" -> "union_fields::TargetTrait" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "union_fields" -> "union_fields::TargetUnion" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge "union_fields" -> "union_fields::Union" [label="owns", color="#000000", style="solid"] [constraint=true]; // "owns" edge + "union_fields::TargetUnion" -> "union_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "union_fields::Union" -> "union_fields::GenericTargetEnum" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "union_fields::Union" -> "union_fields::GenericTargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "union_fields::Union" -> "union_fields::GenericTargetUnion" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "union_fields::Union" -> "union_fields::TargetEnum" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "union_fields::Union" -> "union_fields::TargetStruct" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "union_fields::Union" -> "union_fields::TargetTrait" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge + "union_fields::Union" -> "union_fields::TargetUnion" [label="uses", color="#7f7f7f", style="dashed"] [constraint=false]; // "uses" edge }