aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_db/src/input.rs82
-rw-r--r--crates/ra_hir/src/nameres/tests.rs12
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs31
-rw-r--r--crates/ra_ide_api/src/hover.rs15
-rw-r--r--crates/ra_ide_api/src/runnables.rs5
-rw-r--r--crates/ra_lsp_server/src/cargo_target_spec.rs9
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs74
-rw-r--r--crates/ra_lsp_server/src/server_world.rs25
8 files changed, 167 insertions, 86 deletions
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 023183e29..2b761ea0c 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -53,6 +53,9 @@ pub struct CrateGraph {
53 arena: FxHashMap<CrateId, CrateData>, 53 arena: FxHashMap<CrateId, CrateData>,
54} 54}
55 55
56#[derive(Debug)]
57pub struct CyclicDependencies;
58
56#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 59#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
57pub struct CrateId(pub u32); 60pub struct CrateId(pub u32);
58 61
@@ -94,12 +97,16 @@ impl CrateGraph {
94 assert!(prev.is_none()); 97 assert!(prev.is_none());
95 crate_id 98 crate_id
96 } 99 }
97 pub fn add_dep(&mut self, from: CrateId, name: SmolStr, to: CrateId) { 100 pub fn add_dep(
98 let mut visited = FxHashSet::default(); 101 &mut self,
99 if self.dfs_find(from, to, &mut visited) { 102 from: CrateId,
100 panic!("Cycle dependencies found.") 103 name: SmolStr,
104 to: CrateId,
105 ) -> Result<(), CyclicDependencies> {
106 if self.dfs_find(from, to, &mut FxHashSet::default()) {
107 return Err(CyclicDependencies);
101 } 108 }
102 self.arena.get_mut(&from).unwrap().add_dep(name, to) 109 Ok(self.arena.get_mut(&from).unwrap().add_dep(name, to))
103 } 110 }
104 pub fn is_empty(&self) -> bool { 111 pub fn is_empty(&self) -> bool {
105 self.arena.is_empty() 112 self.arena.is_empty()
@@ -139,35 +146,6 @@ impl CrateGraph {
139 } 146 }
140} 147}
141 148
142#[cfg(test)]
143mod tests {
144 use super::{CrateGraph, FxHashMap, FileId, SmolStr};
145
146 #[test]
147 #[should_panic]
148 fn it_should_painc_because_of_cycle_dependencies() {
149 let mut graph = CrateGraph::default();
150 let crate1 = graph.add_crate_root(FileId(1u32));
151 let crate2 = graph.add_crate_root(FileId(2u32));
152 let crate3 = graph.add_crate_root(FileId(3u32));
153 graph.add_dep(crate1, SmolStr::new("crate2"), crate2);
154 graph.add_dep(crate2, SmolStr::new("crate3"), crate3);
155 graph.add_dep(crate3, SmolStr::new("crate1"), crate1);
156 }
157
158 #[test]
159 fn it_works() {
160 let mut graph = CrateGraph {
161 arena: FxHashMap::default(),
162 };
163 let crate1 = graph.add_crate_root(FileId(1u32));
164 let crate2 = graph.add_crate_root(FileId(2u32));
165 let crate3 = graph.add_crate_root(FileId(3u32));
166 graph.add_dep(crate1, SmolStr::new("crate2"), crate2);
167 graph.add_dep(crate2, SmolStr::new("crate3"), crate3);
168 }
169}
170
171salsa::query_group! { 149salsa::query_group! {
172 pub trait FilesDatabase: salsa::Database { 150 pub trait FilesDatabase: salsa::Database {
173 /// Text of the file. 151 /// Text of the file.
@@ -209,3 +187,39 @@ salsa::query_group! {
209 } 187 }
210 } 188 }
211} 189}
190
191#[cfg(test)]
192mod tests {
193 use super::{CrateGraph, FileId, SmolStr};
194
195 #[test]
196 fn it_should_painc_because_of_cycle_dependencies() {
197 let mut graph = CrateGraph::default();
198 let crate1 = graph.add_crate_root(FileId(1u32));
199 let crate2 = graph.add_crate_root(FileId(2u32));
200 let crate3 = graph.add_crate_root(FileId(3u32));
201 assert!(graph
202 .add_dep(crate1, SmolStr::new("crate2"), crate2)
203 .is_ok());
204 assert!(graph
205 .add_dep(crate2, SmolStr::new("crate3"), crate3)
206 .is_ok());
207 assert!(graph
208 .add_dep(crate3, SmolStr::new("crate1"), crate1)
209 .is_err());
210 }
211
212 #[test]
213 fn it_works() {
214 let mut graph = CrateGraph::default();
215 let crate1 = graph.add_crate_root(FileId(1u32));
216 let crate2 = graph.add_crate_root(FileId(2u32));
217 let crate3 = graph.add_crate_root(FileId(3u32));
218 assert!(graph
219 .add_dep(crate1, SmolStr::new("crate2"), crate2)
220 .is_ok());
221 assert!(graph
222 .add_dep(crate2, SmolStr::new("crate3"), crate3)
223 .is_ok());
224 }
225}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index ba9fcb3d1..647fd92aa 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -235,7 +235,9 @@ fn item_map_across_crates() {
235 let mut crate_graph = CrateGraph::default(); 235 let mut crate_graph = CrateGraph::default();
236 let main_crate = crate_graph.add_crate_root(main_id); 236 let main_crate = crate_graph.add_crate_root(main_id);
237 let lib_crate = crate_graph.add_crate_root(lib_id); 237 let lib_crate = crate_graph.add_crate_root(lib_id);
238 crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate); 238 crate_graph
239 .add_dep(main_crate, "test_crate".into(), lib_crate)
240 .unwrap();
239 241
240 db.set_crate_graph(crate_graph); 242 db.set_crate_graph(crate_graph);
241 243
@@ -288,7 +290,9 @@ fn import_across_source_roots() {
288 let mut crate_graph = CrateGraph::default(); 290 let mut crate_graph = CrateGraph::default();
289 let main_crate = crate_graph.add_crate_root(main_id); 291 let main_crate = crate_graph.add_crate_root(main_id);
290 let lib_crate = crate_graph.add_crate_root(lib_id); 292 let lib_crate = crate_graph.add_crate_root(lib_id);
291 crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate); 293 crate_graph
294 .add_dep(main_crate, "test_crate".into(), lib_crate)
295 .unwrap();
292 296
293 db.set_crate_graph(crate_graph); 297 db.set_crate_graph(crate_graph);
294 298
@@ -330,7 +334,9 @@ fn reexport_across_crates() {
330 let mut crate_graph = CrateGraph::default(); 334 let mut crate_graph = CrateGraph::default();
331 let main_crate = crate_graph.add_crate_root(main_id); 335 let main_crate = crate_graph.add_crate_root(main_id);
332 let lib_crate = crate_graph.add_crate_root(lib_id); 336 let lib_crate = crate_graph.add_crate_root(lib_id);
333 crate_graph.add_dep(main_crate, "test_crate".into(), lib_crate); 337 crate_graph
338 .add_dep(main_crate, "test_crate".into(), lib_crate)
339 .unwrap();
334 340
335 db.set_crate_graph(crate_graph); 341 db.set_crate_graph(crate_graph);
336 342
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 8d2ff561a..e2537758d 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -13,8 +13,11 @@ pub(crate) fn goto_definition(
13 let file = db.source_file(position.file_id); 13 let file = db.source_file(position.file_id);
14 let syntax = file.syntax(); 14 let syntax = file.syntax();
15 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) { 15 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(syntax, position.offset) {
16 let navs = reference_definition(db, position.file_id, name_ref)?; 16 let navs = reference_definition(db, position.file_id, name_ref)?.to_vec();
17 return Ok(Some(RangeInfo::new(name_ref.syntax().range(), navs))); 17 return Ok(Some(RangeInfo::new(
18 name_ref.syntax().range(),
19 navs.to_vec(),
20 )));
18 } 21 }
19 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) { 22 if let Some(name) = find_node_at_offset::<ast::Name>(syntax, position.offset) {
20 let navs = ctry!(name_definition(db, position.file_id, name)?); 23 let navs = ctry!(name_definition(db, position.file_id, name)?);
@@ -23,11 +26,27 @@ pub(crate) fn goto_definition(
23 Ok(None) 26 Ok(None)
24} 27}
25 28
29pub(crate) enum ReferenceResult {
30 Exact(NavigationTarget),
31 Approximate(Vec<NavigationTarget>),
32}
33
34impl ReferenceResult {
35 fn to_vec(self) -> Vec<NavigationTarget> {
36 use self::ReferenceResult::*;
37 match self {
38 Exact(target) => vec![target],
39 Approximate(vec) => vec,
40 }
41 }
42}
43
26pub(crate) fn reference_definition( 44pub(crate) fn reference_definition(
27 db: &RootDatabase, 45 db: &RootDatabase,
28 file_id: FileId, 46 file_id: FileId,
29 name_ref: &ast::NameRef, 47 name_ref: &ast::NameRef,
30) -> Cancelable<Vec<NavigationTarget>> { 48) -> Cancelable<ReferenceResult> {
49 use self::ReferenceResult::*;
31 if let Some(fn_descr) = 50 if let Some(fn_descr) =
32 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())? 51 hir::source_binder::function_from_child_node(db, file_id, name_ref.syntax())?
33 { 52 {
@@ -35,7 +54,7 @@ pub(crate) fn reference_definition(
35 // First try to resolve the symbol locally 54 // First try to resolve the symbol locally
36 if let Some(entry) = scope.resolve_local_name(name_ref) { 55 if let Some(entry) = scope.resolve_local_name(name_ref) {
37 let nav = NavigationTarget::from_scope_entry(file_id, &entry); 56 let nav = NavigationTarget::from_scope_entry(file_id, &entry);
38 return Ok(vec![nav]); 57 return Ok(Exact(nav));
39 }; 58 };
40 } 59 }
41 // Then try module name resolution 60 // Then try module name resolution
@@ -51,7 +70,7 @@ pub(crate) fn reference_definition(
51 let resolved = module.resolve_path(db, &path)?; 70 let resolved = module.resolve_path(db, &path)?;
52 if let Some(def_id) = resolved.take_types().or(resolved.take_values()) { 71 if let Some(def_id) = resolved.take_types().or(resolved.take_values()) {
53 if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)?)? { 72 if let Some(target) = NavigationTarget::from_def(db, def_id.resolve(db)?)? {
54 return Ok(vec![target]); 73 return Ok(Exact(target));
55 } 74 }
56 } 75 }
57 } 76 }
@@ -62,7 +81,7 @@ pub(crate) fn reference_definition(
62 .into_iter() 81 .into_iter()
63 .map(NavigationTarget::from_symbol) 82 .map(NavigationTarget::from_symbol)
64 .collect(); 83 .collect();
65 Ok(navs) 84 Ok(Approximate(navs))
66} 85}
67 86
68fn name_definition( 87fn name_definition(
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index b66774cdf..2968b807c 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -16,9 +16,16 @@ pub(crate) fn hover(
16 16
17 let mut range = None; 17 let mut range = None;
18 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { 18 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
19 let navs = crate::goto_definition::reference_definition(db, position.file_id, name_ref)?; 19 use crate::goto_definition::{ReferenceResult::*, reference_definition};
20 for nav in navs { 20 let ref_result = reference_definition(db, position.file_id, name_ref)?;
21 res.extend(doc_text_for(db, nav)?) 21 match ref_result {
22 Exact(nav) => res.extend(doc_text_for(db, nav)?),
23 Approximate(navs) => {
24 res.push("Failed to exactly resolve the symbol. This is probably because rust_analyzer does not yet support glob imports or traits. \nThese methods were found instead:".to_string());
25 for nav in navs {
26 res.extend(doc_text_for(db, nav)?)
27 }
28 }
22 } 29 }
23 if !res.is_empty() { 30 if !res.is_empty() {
24 range = Some(name_ref.syntax().range()) 31 range = Some(name_ref.syntax().range())
@@ -34,7 +41,7 @@ pub(crate) fn hover(
34 file_id: position.file_id, 41 file_id: position.file_id,
35 range: node.range(), 42 range: node.range(),
36 }; 43 };
37 res.extend(type_of(db, frange)?); 44 res.extend(type_of(db, frange)?.map(Into::into));
38 range = Some(node.range()); 45 range = Some(node.range());
39 }; 46 };
40 47
diff --git a/crates/ra_ide_api/src/runnables.rs b/crates/ra_ide_api/src/runnables.rs
index 98b1d2d55..53e49da5b 100644
--- a/crates/ra_ide_api/src/runnables.rs
+++ b/crates/ra_ide_api/src/runnables.rs
@@ -17,6 +17,7 @@ pub struct Runnable {
17pub enum RunnableKind { 17pub enum RunnableKind {
18 Test { name: String }, 18 Test { name: String },
19 TestMod { path: String }, 19 TestMod { path: String },
20 Bench { name: String },
20 Bin, 21 Bin,
21} 22}
22 23
@@ -48,6 +49,10 @@ fn runnable_fn(fn_def: &ast::FnDef) -> Option<Runnable> {
48 RunnableKind::Test { 49 RunnableKind::Test {
49 name: name.to_string(), 50 name: name.to_string(),
50 } 51 }
52 } else if fn_def.has_atom_attr("bench") {
53 RunnableKind::Bench {
54 name: name.to_string(),
55 }
51 } else { 56 } else {
52 return None; 57 return None;
53 }; 58 };
diff --git a/crates/ra_lsp_server/src/cargo_target_spec.rs b/crates/ra_lsp_server/src/cargo_target_spec.rs
index a66f14b82..db9496bbe 100644
--- a/crates/ra_lsp_server/src/cargo_target_spec.rs
+++ b/crates/ra_lsp_server/src/cargo_target_spec.rs
@@ -32,6 +32,15 @@ pub(crate) fn runnable_args(
32 res.push(path.to_string()); 32 res.push(path.to_string());
33 res.push("--nocapture".to_string()); 33 res.push("--nocapture".to_string());
34 } 34 }
35 RunnableKind::Bench { name } => {
36 res.push("bench".to_string());
37 if let Some(spec) = spec {
38 spec.push_to(&mut res);
39 }
40 res.push("--".to_string());
41 res.push(name.to_string());
42 res.push("--nocapture".to_string());
43 }
35 RunnableKind::Bin => { 44 RunnableKind::Bin => {
36 res.push("run".to_string()); 45 res.push("run".to_string());
37 if let Some(spec) = spec { 46 if let Some(spec) = spec {
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index a781df181..7326a727d 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -2,22 +2,23 @@ use std::collections::HashMap;
2 2
3use gen_lsp_server::ErrorCode; 3use gen_lsp_server::ErrorCode;
4use languageserver_types::{ 4use languageserver_types::{
5 CodeActionResponse, Command, CodeLens, Diagnostic, DiagnosticSeverity, DocumentFormattingParams, 5 CodeActionResponse, CodeLens, Command, Diagnostic, DiagnosticSeverity,
6 DocumentHighlight, DocumentSymbol, Documentation, FoldingRange, FoldingRangeKind, 6 DocumentFormattingParams, DocumentHighlight, DocumentSymbol, Documentation, FoldingRange,
7 FoldingRangeParams, Hover, HoverContents, Location, MarkupContent, MarkupKind, 7 FoldingRangeKind, FoldingRangeParams, Hover, HoverContents, Location, MarkupContent,
8 ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range, RenameParams, 8 MarkupKind, ParameterInformation, ParameterLabel, Position, PrepareRenameResponse, Range,
9 SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit, WorkspaceEdit, 9 RenameParams, SignatureInformation, SymbolInformation, TextDocumentIdentifier, TextEdit,
10 WorkspaceEdit,
10}; 11};
11use ra_ide_api::{ 12use ra_ide_api::{
12 FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity, RangeInfo, 13 FileId, FilePosition, FileRange, FoldKind, Query, RangeInfo, RunnableKind, Severity,
13}; 14};
14use ra_syntax::{TextUnit, AstNode}; 15use ra_syntax::{AstNode, TextUnit};
15use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
16use serde_json::to_value; 17use serde_json::to_value;
17use std::io::Write; 18use std::io::Write;
18 19
19use crate::{ 20use crate::{
20 cargo_target_spec::{CargoTargetSpec, runnable_args}, 21 cargo_target_spec::{runnable_args, CargoTargetSpec},
21 conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith}, 22 conv::{to_location, to_location_link, Conv, ConvWith, MapConvWith, TryConvWith},
22 req::{self, Decoration}, 23 req::{self, Decoration},
23 server_world::ServerWorld, 24 server_world::ServerWorld,
@@ -258,6 +259,7 @@ pub fn handle_runnables(
258 label: match &runnable.kind { 259 label: match &runnable.kind {
259 RunnableKind::Test { name } => format!("test {}", name), 260 RunnableKind::Test { name } => format!("test {}", name),
260 RunnableKind::TestMod { path } => format!("test-mod {}", path), 261 RunnableKind::TestMod { path } => format!("test-mod {}", path),
262 RunnableKind::Bench { name } => format!("bench {}", name),
261 RunnableKind::Bin => "run binary".to_string(), 263 RunnableKind::Bin => "run binary".to_string(),
262 }, 264 },
263 bin: "cargo".to_string(), 265 bin: "cargo".to_string(),
@@ -586,35 +588,37 @@ pub fn handle_code_lens(
586 let mut lenses: Vec<CodeLens> = Default::default(); 588 let mut lenses: Vec<CodeLens> = Default::default();
587 589
588 for runnable in world.analysis().runnables(file_id)? { 590 for runnable in world.analysis().runnables(file_id)? {
589 match &runnable.kind { 591 let title = match &runnable.kind {
590 RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => { 592 RunnableKind::Test { name: _ } | RunnableKind::TestMod { path: _ } => Some("Run Test"),
591 let args = runnable_args(&world, file_id, &runnable.kind)?; 593 RunnableKind::Bench { name: _ } => Some("Run Bench"),
592 594 _ => None,
593 let range = runnable.range.conv_with(&line_index); 595 };
594
595 // This represents the actual command that will be run.
596 let r: req::Runnable = req::Runnable {
597 range,
598 label: Default::default(),
599 bin: "cargo".into(),
600 args,
601 env: Default::default(),
602 };
603 596
604 let lens = CodeLens { 597 if let Some(title) = title {
605 range, 598 let args = runnable_args(&world, file_id, &runnable.kind)?;
606 command: Some(Command { 599 let range = runnable.range.conv_with(&line_index);
607 title: "Run Test".into(), 600
608 command: "ra-lsp.run-single".into(), 601 // This represents the actual command that will be run.
609 arguments: Some(vec![to_value(r).unwrap()]), 602 let r: req::Runnable = req::Runnable {
610 }), 603 range,
611 data: None, 604 label: Default::default(),
612 }; 605 bin: "cargo".into(),
606 args,
607 env: Default::default(),
608 };
613 609
614 lenses.push(lens); 610 let lens = CodeLens {
615 } 611 range,
616 _ => continue, 612 command: Some(Command {
617 }; 613 title: title.into(),
614 command: "ra-lsp.run-single".into(),
615 arguments: Some(vec![to_value(r).unwrap()]),
616 }),
617 data: None,
618 };
619
620 lenses.push(lens);
621 }
618 } 622 }
619 623
620 return Ok(Some(lenses)); 624 return Ok(Some(lenses));
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs
index 4f3c231d3..d5dbf999f 100644
--- a/crates/ra_lsp_server/src/server_world.rs
+++ b/crates/ra_lsp_server/src/server_world.rs
@@ -73,7 +73,9 @@ impl ServerWorldState {
73 if let (Some(&from), Some(&to)) = 73 if let (Some(&from), Some(&to)) =
74 (sysroot_crates.get(&from), sysroot_crates.get(&to)) 74 (sysroot_crates.get(&from), sysroot_crates.get(&to))
75 { 75 {
76 crate_graph.add_dep(from, name.clone(), to); 76 if let Err(_) = crate_graph.add_dep(from, name.clone(), to) {
77 log::error!("cyclic dependency between sysroot crates")
78 }
77 } 79 }
78 } 80 }
79 } 81 }
@@ -108,11 +110,20 @@ impl ServerWorldState {
108 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 110 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
109 if let Some(to) = lib_tgt { 111 if let Some(to) = lib_tgt {
110 if to != from { 112 if to != from {
111 crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to); 113 if let Err(_) =
114 crate_graph.add_dep(from, pkg.name(&ws.cargo).into(), to)
115 {
116 log::error!(
117 "cyclic dependency between targets of {}",
118 pkg.name(&ws.cargo)
119 )
120 }
112 } 121 }
113 } 122 }
114 if let Some(std) = libstd { 123 if let Some(std) = libstd {
115 crate_graph.add_dep(from, "std".into(), std); 124 if let Err(_) = crate_graph.add_dep(from, "std".into(), std) {
125 log::error!("cyclic dependency on std for {}", pkg.name(&ws.cargo))
126 }
116 } 127 }
117 } 128 }
118 } 129 }
@@ -123,7 +134,13 @@ impl ServerWorldState {
123 for dep in pkg.dependencies(&ws.cargo) { 134 for dep in pkg.dependencies(&ws.cargo) {
124 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { 135 if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
125 for &from in pkg_crates.get(&pkg).into_iter().flatten() { 136 for &from in pkg_crates.get(&pkg).into_iter().flatten() {
126 crate_graph.add_dep(from, dep.name.clone(), to); 137 if let Err(_) = crate_graph.add_dep(from, dep.name.clone(), to) {
138 log::error!(
139 "cyclic dependency {} -> {}",
140 pkg.name(&ws.cargo),
141 dep.pkg.name(&ws.cargo)
142 )
143 }
127 } 144 }
128 } 145 }
129 } 146 }