diff --git a/src/Cargo.lock b/src/Cargo.lock index 8bf4b6ad3e0c7..efbbe36c981a8 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1040,7 +1040,7 @@ dependencies = [ [[package]] name = "rls-data" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1049,7 +1049,7 @@ dependencies = [ [[package]] name = "rls-data" -version = "0.4.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1372,7 +1372,7 @@ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2076,8 +2076,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9191b1f57603095f105d317e375d19b1c9c5c3185ea9633a99a6dcbed04457" "checksum rls-analysis 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d77d58e8933752142b5b92e3f8ba6d6f1630be6da5627c492268a43f79ffbda" -"checksum rls-data 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc4277ce3c57f456b11fe3145b181a844a25201bab5cbaa1978457e6e2f27d47" "checksum rls-data 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "374a8fad31cc0681a7bfd8a04079dd4afd0e981d34e18a171b1a467445bdf51e" +"checksum rls-data 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e2087477364c34faca86c2476765deb1185dbae3c598cfb1eb040f3a74d22b5" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" "checksum rls-vfs 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ace07060dd154731b39254864245cbdd33c8f5f64fe1f630a089c72e2468f854" "checksum rustc-demangle 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3058a43ada2c2d0b92b3ae38007a2d0fa5e9db971be260e0171408a4ff471c95" diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml index 6d04bff82829a..53a82cf73e95b 100644 --- a/src/librustc_save_analysis/Cargo.toml +++ b/src/librustc_save_analysis/Cargo.toml @@ -14,7 +14,7 @@ rustc = { path = "../librustc" } rustc_typeck = { path = "../librustc_typeck" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } -rls-data = "0.3" +rls-data = "0.6" rls-span = "0.4" # FIXME(#40527) should move rustc serialize out of tree rustc-serialize = "0.3" diff --git a/src/librustc_save_analysis/data.rs b/src/librustc_save_analysis/data.rs index cac1a2e3c5af1..e15e3f6e79e26 100644 --- a/src/librustc_save_analysis/data.rs +++ b/src/librustc_save_analysis/data.rs @@ -18,7 +18,7 @@ use rustc::hir::def_id::{CrateNum, DefId}; use syntax::ast::{self, Attribute, NodeId}; use syntax_pos::Span; -use rls_data::ExternalCrateData; +use rls_data::{ExternalCrateData, Signature}; pub struct CrateData { pub name: String, @@ -129,7 +129,7 @@ pub struct EnumData { pub variants: Vec, pub visibility: Visibility, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -165,7 +165,7 @@ pub struct FunctionData { pub visibility: Visibility, pub parent: Option, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -251,7 +251,7 @@ pub struct MethodData { pub parent: Option, pub visibility: Visibility, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -292,7 +292,7 @@ pub struct StructData { pub fields: Vec, pub visibility: Visibility, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -307,7 +307,7 @@ pub struct StructVariantData { pub scope: NodeId, pub parent: Option, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -322,7 +322,7 @@ pub struct TraitData { pub items: Vec, pub visibility: Visibility, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -337,7 +337,7 @@ pub struct TupleVariantData { pub scope: NodeId, pub parent: Option, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -419,28 +419,3 @@ pub struct VariableRefData { pub scope: NodeId, pub ref_id: DefId, } - - -/// Encodes information about the signature of a definition. This should have -/// enough information to create a nice display about a definition without -/// access to the source code. -#[derive(Clone, Debug)] -pub struct Signature { - pub span: Span, - pub text: String, - // These identify the main identifier for the defintion as byte offsets into - // `text`. E.g., of `foo` in `pub fn foo(...)` - pub ident_start: usize, - pub ident_end: usize, - pub defs: Vec, - pub refs: Vec, -} - -/// An element of a signature. `start` and `end` are byte offsets into the `text` -/// of the parent `Signature`. -#[derive(Clone, Debug)] -pub struct SigElement { - pub id: DefId, - pub start: usize, - pub end: usize, -} diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs index a95236e2a5072..ea346d99e31b5 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/src/librustc_save_analysis/dump_visitor.rs @@ -48,12 +48,13 @@ use syntax::ptr::P; use syntax::codemap::Spanned; use syntax_pos::*; -use super::{escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; -use super::data::*; -use super::dump::Dump; -use super::external_data::{Lower, make_def_id}; -use super::span_utils::SpanUtils; -use super::recorder; +use {escape, generated_code, SaveContext, PathCollector, docs_for_attrs}; +use data::*; +use dump::Dump; +use external_data::{Lower, make_def_id}; +use recorder; +use span_utils::SpanUtils; +use sig; use rls_data::ExternalCrateData; @@ -391,13 +392,13 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { sig: &'l ast::MethodSig, body: Option<&'l ast::Block>, id: ast::NodeId, - name: ast::Name, + name: ast::Ident, vis: Visibility, attrs: &'l [Attribute], span: Span) { debug!("process_method: {}:{}", id, name); - if let Some(method_data) = self.save_ctxt.get_method_data(id, name, span) { + if let Some(method_data) = self.save_ctxt.get_method_data(id, name.name, span) { let sig_str = ::make_signature(&sig.decl, &sig.generics); if body.is_some() { @@ -423,7 +424,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { Some(id) => { for item in self.tcx.associated_items(id) { if item.kind == ty::AssociatedKind::Method { - if item.name == name { + if item.name == name.name { decl_id = Some(item.def_id); break; } @@ -455,7 +456,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { parent: trait_id, visibility: vis, docs: docs_for_attrs(attrs), - sig: method_data.sig, + sig: sig::method_signature(id, name, sig, &self.save_ctxt), attributes: attrs.to_vec(), }.lower(self.tcx)); } @@ -580,13 +581,14 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { name: ast::Name, span: Span, typ: &'l ast::Ty, - expr: &'l ast::Expr, + expr: Option<&'l ast::Expr>, parent_id: DefId, vis: Visibility, attrs: &'l [Attribute]) { let qualname = format!("::{}", self.tcx.node_path_str(id)); let sub_span = self.span.sub_span_after_keyword(span, keywords::Const); + let value = expr.map(|e| self.span.snippet(e.span)).unwrap_or(String::new()); if !self.span.filter_generated(sub_span, span) { self.dumper.variable(VariableData { @@ -595,20 +597,22 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { id: id, name: name.to_string(), qualname: qualname, - value: self.span.snippet(expr.span), + value: value, type_value: ty_to_string(&typ), scope: self.cur_scope, parent: Some(parent_id), visibility: vis, docs: docs_for_attrs(attrs), - sig: None, + sig: sig::assoc_const_signature(id, name, typ, expr, &self.save_ctxt), attributes: attrs.to_vec(), }.lower(self.tcx)); } // walk type and init value self.visit_ty(typ); - self.visit_expr(expr); + if let Some(expr) = expr { + self.visit_expr(expr); + } } // FIXME tuple structs should generate tuple-specific data. @@ -646,7 +650,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { fields: fields, visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), - sig: self.save_ctxt.sig_base(item), + sig: sig::item_signature(item, &self.save_ctxt), attributes: item.attrs.clone(), }.lower(self.tcx)); } @@ -679,18 +683,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { qualname.push_str("::"); qualname.push_str(&name); - let text = self.span.signature_string_for_span(variant.span); - let ident_start = text.find(&name).unwrap(); - let ident_end = ident_start + name.len(); - let sig = Signature { - span: variant.span, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - }; - match variant.node.data { ast::VariantData::Struct(ref fields, _) => { let sub_span = self.span.span_for_first_ident(variant.span); @@ -712,7 +704,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: enum_data.scope, parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), - sig: sig, + sig: sig::variant_signature(variant, &self.save_ctxt), attributes: variant.node.attrs.clone(), }.lower(self.tcx)); } @@ -739,7 +731,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { scope: enum_data.scope, parent: Some(make_def_id(item.id, &self.tcx.hir)), docs: docs_for_attrs(&variant.node.attrs), - sig: sig, + sig: sig::variant_signature(variant, &self.save_ctxt), attributes: variant.node.attrs.clone(), }.lower(self.tcx)); } @@ -811,7 +803,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { items: methods.iter().map(|i| i.id).collect(), visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), - sig: self.save_ctxt.sig_base(item), + sig: sig::item_signature(item, &self.save_ctxt), attributes: item.attrs.clone(), }.lower(self.tcx)); } @@ -1133,12 +1125,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { fn process_trait_item(&mut self, trait_item: &'l ast::TraitItem, trait_id: DefId) { self.process_macro_use(trait_item.span, trait_item.id); match trait_item.node { - ast::TraitItemKind::Const(ref ty, Some(ref expr)) => { + ast::TraitItemKind::Const(ref ty, ref expr) => { self.process_assoc_const(trait_item.id, trait_item.ident.name, trait_item.span, &ty, - &expr, + expr.as_ref().map(|e| &**e), trait_id, Visibility::Public, &trait_item.attrs); @@ -1147,12 +1139,12 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.process_method(sig, body.as_ref().map(|x| &**x), trait_item.id, - trait_item.ident.name, + trait_item.ident, Visibility::Public, &trait_item.attrs, trait_item.span); } - ast::TraitItemKind::Type(ref _bounds, ref default_ty) => { + ast::TraitItemKind::Type(ref bounds, ref default_ty) => { // FIXME do something with _bounds (for type refs) let name = trait_item.ident.name.to_string(); let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id)); @@ -1168,7 +1160,11 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { visibility: Visibility::Public, parent: Some(trait_id), docs: docs_for_attrs(&trait_item.attrs), - sig: None, + sig: sig::assoc_type_signature(trait_item.id, + trait_item.ident, + Some(bounds), + default_ty.as_ref().map(|ty| &**ty), + &self.save_ctxt), attributes: trait_item.attrs.clone(), }.lower(self.tcx)); } @@ -1177,7 +1173,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.visit_ty(default_ty) } } - ast::TraitItemKind::Const(ref ty, None) => self.visit_ty(ty), ast::TraitItemKind::Macro(_) => {} } } @@ -1190,7 +1185,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { impl_item.ident.name, impl_item.span, &ty, - &expr, + Some(expr), impl_id, From::from(&impl_item.vis), &impl_item.attrs); @@ -1199,12 +1194,17 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> { self.process_method(sig, Some(body), impl_item.id, - impl_item.ident.name, + impl_item.ident, From::from(&impl_item.vis), &impl_item.attrs, impl_item.span); } - ast::ImplItemKind::Type(ref ty) => self.visit_ty(ty), + ast::ImplItemKind::Type(ref ty) => { + // FIXME uses of the assoc type should ideally point to this + // 'def' and the name here should be a ref to the def in the + // trait. + self.visit_ty(ty) + } ast::ImplItemKind::Macro(_) => {} } } @@ -1369,7 +1369,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll, visibility: From::from(&item.vis), parent: None, docs: docs_for_attrs(&item.attrs), - sig: Some(self.save_ctxt.sig_base(item)), + sig: sig::item_signature(item, &self.save_ctxt), attributes: item.attrs.clone(), }.lower(self.tcx)); } diff --git a/src/librustc_save_analysis/external_data.rs b/src/librustc_save_analysis/external_data.rs index 02441a0587eb6..245a3bcc61795 100644 --- a/src/librustc_save_analysis/external_data.rs +++ b/src/librustc_save_analysis/external_data.rs @@ -16,9 +16,9 @@ use syntax::codemap::CodeMap; use syntax::print::pprust; use syntax_pos::Span; -use data::{self, Visibility, SigElement}; +use data::{self, Visibility}; -use rls_data::{SpanData, CratePreludeData, Attribute}; +use rls_data::{SpanData, CratePreludeData, Attribute, Signature}; use rls_span::{Column, Row}; // FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet @@ -103,7 +103,7 @@ pub struct EnumData { pub variants: Vec, pub visibility: Visibility, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -121,7 +121,7 @@ impl Lower for data::EnumData { variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), visibility: self.visibility, docs: self.docs, - sig: self.sig.lower(tcx), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -186,7 +186,7 @@ pub struct FunctionData { pub visibility: Visibility, pub parent: Option, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -205,7 +205,7 @@ impl Lower for data::FunctionData { visibility: self.visibility, parent: self.parent, docs: self.docs, - sig: self.sig.lower(tcx), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -355,7 +355,7 @@ pub struct MethodData { pub visibility: Visibility, pub parent: Option, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -374,7 +374,7 @@ impl Lower for data::MethodData { visibility: self.visibility, parent: self.parent, docs: self.docs, - sig: self.sig.lower(tcx), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -410,7 +410,7 @@ impl Lower for data::ModData { items: self.items.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), visibility: self.visibility, docs: self.docs, - sig: self.sig.map(|s| s.lower(tcx)), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -450,7 +450,7 @@ pub struct StructData { pub fields: Vec, pub visibility: Visibility, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -469,7 +469,7 @@ impl Lower for data::StructData { fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), visibility: self.visibility, docs: self.docs, - sig: self.sig.lower(tcx), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -486,7 +486,7 @@ pub struct StructVariantData { pub scope: DefId, pub parent: Option, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -504,7 +504,7 @@ impl Lower for data::StructVariantData { scope: make_def_id(self.scope, &tcx.hir), parent: self.parent, docs: self.docs, - sig: self.sig.lower(tcx), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -521,7 +521,7 @@ pub struct TraitData { pub items: Vec, pub visibility: Visibility, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -539,7 +539,7 @@ impl Lower for data::TraitData { items: self.items.into_iter().map(|id| make_def_id(id, &tcx.hir)).collect(), visibility: self.visibility, docs: self.docs, - sig: self.sig.lower(tcx), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -556,7 +556,7 @@ pub struct TupleVariantData { pub scope: DefId, pub parent: Option, pub docs: String, - pub sig: Signature, + pub sig: Option, pub attributes: Vec, } @@ -574,7 +574,7 @@ impl Lower for data::TupleVariantData { scope: make_def_id(self.scope, &tcx.hir), parent: self.parent, docs: self.docs, - sig: self.sig.lower(tcx), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -608,7 +608,7 @@ impl Lower for data::TypeDefData { visibility: self.visibility, parent: self.parent, docs: self.docs, - sig: self.sig.map(|s| s.lower(tcx)), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -718,7 +718,7 @@ impl Lower for data::VariableData { parent: self.parent, visibility: self.visibility, docs: self.docs, - sig: self.sig.map(|s| s.lower(tcx)), + sig: self.sig, attributes: self.attributes.lower(tcx), } } @@ -746,30 +746,3 @@ impl Lower for data::VariableRefData { } } } - -#[derive(Clone, Debug)] -pub struct Signature { - pub span: SpanData, - pub text: String, - // These identify the main identifier for the defintion as byte offsets into - // `text`. E.g., of `foo` in `pub fn foo(...)` - pub ident_start: usize, - pub ident_end: usize, - pub defs: Vec, - pub refs: Vec, -} - -impl Lower for data::Signature { - type Target = Signature; - - fn lower(self, tcx: TyCtxt) -> Signature { - Signature { - span: span_from_span(self.span, tcx.sess.codemap()), - text: self.text, - ident_start: self.ident_start, - ident_end: self.ident_end, - defs: self.defs, - refs: self.refs, - } - } -} diff --git a/src/librustc_save_analysis/json_api_dumper.rs b/src/librustc_save_analysis/json_api_dumper.rs index 49b14f5eca072..bddee6460ff9c 100644 --- a/src/librustc_save_analysis/json_api_dumper.rs +++ b/src/librustc_save_analysis/json_api_dumper.rs @@ -15,9 +15,9 @@ use rustc_serialize::json::as_json; use external_data::*; use data::{VariableKind, Visibility}; use dump::Dump; -use json_dumper::id_from_def_id; +use id_from_def_id; -use rls_data::{Analysis, Import, ImportKind, Def, DefKind, CratePreludeData}; +use rls_data::{Analysis, Import, ImportKind, Def, DefKind, CratePreludeData, Format}; // A dumper to dump a restricted set of JSON information, designed for use with @@ -33,7 +33,9 @@ pub struct JsonApiDumper<'b, W: Write + 'b> { impl<'b, W: Write> JsonApiDumper<'b, W> { pub fn new(writer: &'b mut W) -> JsonApiDumper<'b, W> { - JsonApiDumper { output: writer, result: Analysis::new() } + let mut result = Analysis::new(); + result.kind = Format::JsonApi; + JsonApiDumper { output: writer, result } } } @@ -133,7 +135,7 @@ impl Into> for EnumData { children: self.variants.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: vec![], }), _ => None, @@ -154,7 +156,7 @@ impl Into> for TupleVariantData { children: vec![], decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: vec![], }) } @@ -172,7 +174,7 @@ impl Into> for StructVariantData { children: vec![], decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: vec![], }) } @@ -191,7 +193,7 @@ impl Into> for StructData { children: self.fields.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: vec![], }), _ => None, @@ -212,7 +214,7 @@ impl Into> for TraitData { parent: None, decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: vec![], }), _ => None, @@ -233,7 +235,7 @@ impl Into> for FunctionData { parent: self.parent.map(|id| id_from_def_id(id)), decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: vec![], }), _ => None, @@ -254,7 +256,7 @@ impl Into> for MethodData { parent: self.parent.map(|id| id_from_def_id(id)), decl_id: self.decl_id.map(|id| id_from_def_id(id)), docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: vec![], }), _ => None, diff --git a/src/librustc_save_analysis/json_dumper.rs b/src/librustc_save_analysis/json_dumper.rs index eaa0c0825f0e9..58df612c687c3 100644 --- a/src/librustc_save_analysis/json_dumper.rs +++ b/src/librustc_save_analysis/json_dumper.rs @@ -10,17 +10,16 @@ use std::io::Write; -use rustc::hir::def_id::DefId; use rustc_serialize::json::as_json; use rls_data::{self, Id, Analysis, Import, ImportKind, Def, DefKind, Ref, RefKind, MacroRef, - Relation, RelationKind, Signature, SigElement, CratePreludeData}; + Relation, RelationKind, CratePreludeData}; use rls_span::{Column, Row}; -use external_data; use external_data::*; -use data::{self, VariableKind}; +use data::VariableKind; use dump::Dump; +use id_from_def_id; pub struct JsonDumper { result: Analysis, @@ -121,7 +120,7 @@ impl<'b, O: DumpOutput + 'b> Dump for JsonDumper { children: data.items.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, docs: data.docs, - sig: data.sig.map(|s| s.into()), + sig: data.sig, attributes: data.attributes.into_iter().map(|a| a.into()).collect(), }; if def.span.file_name.to_str().unwrap() != def.value { @@ -164,15 +163,6 @@ impl<'b, O: DumpOutput + 'b> Dump for JsonDumper { // method, but not the supplied method). In both cases, we are currently // ignoring it. -// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore -// we use our own Id which is the same, but without the newtype. -pub fn id_from_def_id(id: DefId) -> Id { - Id { - krate: id.krate.as_u32(), - index: id.index.as_u32(), - } -} - impl Into for ExternCrateData { fn into(self) -> Import { Import { @@ -220,7 +210,7 @@ impl Into for EnumData { children: self.variants.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: self.attributes, } } @@ -239,7 +229,7 @@ impl Into for TupleVariantData { children: vec![], decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: self.attributes, } } @@ -257,7 +247,7 @@ impl Into for StructVariantData { children: vec![], decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: self.attributes, } } @@ -275,7 +265,7 @@ impl Into for StructData { children: self.fields.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: self.attributes, } } @@ -293,7 +283,7 @@ impl Into for TraitData { children: self.items.into_iter().map(|id| id_from_def_id(id)).collect(), decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: self.attributes, } } @@ -311,7 +301,7 @@ impl Into for FunctionData { children: vec![], decl_id: None, docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: self.attributes, } } @@ -329,7 +319,7 @@ impl Into for MethodData { children: vec![], decl_id: self.decl_id.map(|id| id_from_def_id(id)), docs: self.docs, - sig: Some(self.sig.into()), + sig: self.sig, attributes: self.attributes, } } @@ -365,7 +355,7 @@ impl Into for TypeDefData { children: vec![], decl_id: None, docs: String::new(), - sig: self.sig.map(|s| s.into()), + sig: self.sig, attributes: self.attributes, } } @@ -480,26 +470,3 @@ impl Into for InheritanceData { } } } - -impl Into for external_data::Signature { - fn into(self) -> Signature { - Signature { - span: self.span, - text: self.text, - ident_start: self.ident_start, - ident_end: self.ident_end, - defs: self.defs.into_iter().map(|s| s.into()).collect(), - refs: self.refs.into_iter().map(|s| s.into()).collect(), - } - } -} - -impl Into for data::SigElement { - fn into(self) -> SigElement { - SigElement { - id: id_from_def_id(self.id), - start: self.start, - end: self.end, - } - } -} diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index b74d3982d61c5..4802494f08ead 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -44,6 +44,7 @@ mod dump_visitor; pub mod external_data; #[macro_use] pub mod span_utils; +mod sig; use rustc::hir; use rustc::hir::def::Def; @@ -140,7 +141,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), parent: None, docs: docs_for_attrs(&item.attrs), - sig: self.sig_base_extern(item), + sig: sig::foreign_item_signature(item, self), attributes: item.attrs.clone(), })) } @@ -160,7 +161,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { type_value: ty_to_string(ty), visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), - sig: Some(self.sig_base_extern(item)), + sig: sig::foreign_item_signature(item, self), attributes: item.attrs.clone(), })) } @@ -186,7 +187,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: From::from(&item.vis), parent: None, docs: docs_for_attrs(&item.attrs), - sig: self.sig_base(item), + sig: sig::item_signature(item, self), attributes: item.attrs.clone(), })) } @@ -215,7 +216,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { type_value: ty_to_string(&typ), visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), - sig: Some(self.sig_base(item)), + sig: sig::item_signature(item, self), attributes: item.attrs.clone(), })) } @@ -235,7 +236,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { type_value: ty_to_string(&typ), visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), - sig: Some(self.sig_base(item)), + sig: sig::item_signature(item, self), attributes: item.attrs.clone(), })) } @@ -258,7 +259,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { items: m.items.iter().map(|i| i.id).collect(), visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), - sig: Some(self.sig_base(item)), + sig: sig::item_signature(item, self), attributes: item.attrs.clone(), })) } @@ -282,7 +283,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { variants: def.variants.iter().map(|v| v.node.data.id()).collect(), visibility: From::from(&item.vis), docs: docs_for_attrs(&item.attrs), - sig: self.sig_base(item), + sig: sig::item_signature(item, self), attributes: item.attrs.clone(), })) } @@ -346,18 +347,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let def_id = self.tcx.hir.local_def_id(field.id); let typ = self.tcx.type_of(def_id).to_string(); - let span = field.span; - let text = self.span_utils.snippet(field.span); - let ident_start = text.find(&name).unwrap(); - let ident_end = ident_start + name.len(); - let sig = Signature { - span: span, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - }; Some(VariableData { id: field.id, kind: VariableKind::Field, @@ -370,7 +359,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { type_value: typ, visibility: From::from(&field.vis), docs: docs_for_attrs(&field.attrs), - sig: Some(sig), + sig: sig::field_signature(field, self), attributes: field.attrs.clone(), }) } else { @@ -380,8 +369,11 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { // FIXME would be nice to take a MethodItem here, but the ast provides both // trait and impl flavours, so the caller must do the disassembly. - pub fn get_method_data(&self, id: ast::NodeId, - name: ast::Name, span: Span) -> Option { + pub fn get_method_data(&self, + id: ast::NodeId, + name: ast::Name, + span: Span) + -> Option { // The qualname for a method is the trait name or name of the struct in an impl in // which the method is declared in, followed by the method's name. let (qualname, parent_scope, decl_id, vis, docs, attributes) = @@ -459,22 +451,9 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn); filter!(self.span_utils, sub_span, span, None); - let name = name.to_string(); - let text = self.span_utils.signature_string_for_span(span); - let ident_start = text.find(&name).unwrap(); - let ident_end = ident_start + name.len(); - let sig = Signature { - span: span, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - }; - Some(FunctionData { id: id, - name: name, + name: name.to_string(), qualname: qualname, declaration: decl_id, span: sub_span.unwrap(), @@ -484,7 +463,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { visibility: vis, parent: parent_scope, docs: docs, - sig: sig, + sig: None, attributes: attributes, }) } @@ -786,36 +765,6 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } - fn sig_base(&self, item: &ast::Item) -> Signature { - let text = self.span_utils.signature_string_for_span(item.span); - let name = item.ident.to_string(); - let ident_start = text.find(&name).expect("Name not in signature?"); - let ident_end = ident_start + name.len(); - Signature { - span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - } - } - - fn sig_base_extern(&self, item: &ast::ForeignItem) -> Signature { - let text = self.span_utils.signature_string_for_span(item.span); - let name = item.ident.to_string(); - let ident_start = text.find(&name).expect("Name not in signature?"); - let ident_end = ident_start + name.len(); - Signature { - span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span }, - text: text, - ident_start: ident_start, - ident_end: ident_end, - defs: vec![], - refs: vec![], - } - } - #[inline] pub fn enclosing_scope(&self, id: NodeId) -> NodeId { self.tcx.hir.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID) @@ -1076,6 +1025,20 @@ fn escape(s: String) -> String { // Helper function to determine if a span came from a // macro expansion or syntax extension. -pub fn generated_code(span: Span) -> bool { +fn generated_code(span: Span) -> bool { span.ctxt != NO_EXPANSION || span == DUMMY_SP } + +// DefId::index is a newtype and so the JSON serialisation is ugly. Therefore +// we use our own Id which is the same, but without the newtype. +fn id_from_def_id(id: DefId) -> rls_data::Id { + rls_data::Id { + krate: id.krate.as_u32(), + index: id.index.as_u32(), + } +} + +fn id_from_node_id(id: NodeId, scx: &SaveContext) -> rls_data::Id { + let def_id = scx.tcx.hir.local_def_id(id); + id_from_def_id(def_id) +} diff --git a/src/librustc_save_analysis/sig.rs b/src/librustc_save_analysis/sig.rs new file mode 100644 index 0000000000000..1d03ab1383af1 --- /dev/null +++ b/src/librustc_save_analysis/sig.rs @@ -0,0 +1,925 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A signature is a string representation of an item's type signature, excluding +// any body. It also includes ids for any defs or refs in the signature. For +// example: +// +// ``` +// fn foo(x: String) { +// println!("{}", x); +// } +// ``` +// The signature string is something like "fn foo(x: String) {}" and the signature +// will have defs for `foo` and `x` and a ref for `String`. +// +// All signature text should parse in the correct context (i.e., in a module or +// impl, etc.). Clients may want to trim trailing `{}` or `;`. The text of a +// signature is not guaranteed to be stable (it may improve or change as the +// syntax changes, or whitespace or punctuation may change). It is also likely +// not to be pretty - no attempt is made to prettify the text. It is recommended +// that clients run the text through Rustfmt. +// +// This module generates Signatures for items by walking the AST and looking up +// references. +// +// Signatures do not include visibility info. I'm not sure if this is a feature +// or an ommission (FIXME). +// +// FIXME where clauses need implementing, defs/refs in generics are mostly missing. + +use {SaveContext, id_from_def_id, id_from_node_id}; + +use rls_data::{Signature, SigElement}; + +use rustc::hir::def::Def; +use syntax::ast::{self, NodeId}; +use syntax::print::pprust; + + +pub fn item_signature(item: &ast::Item, scx: &SaveContext) -> Option { + item.make(0, None, scx).ok() +} + +pub fn foreign_item_signature(item: &ast::ForeignItem, scx: &SaveContext) -> Option { + item.make(0, None, scx).ok() +} + +/// Signature for a struct or tuple field declaration. +/// Does not include a trailing comma. +pub fn field_signature(field: &ast::StructField, scx: &SaveContext) -> Option { + field.make(0, None, scx).ok() +} + +/// Does not include a trailing comma. +pub fn variant_signature(variant: &ast::Variant, scx: &SaveContext) -> Option { + variant.node.make(0, None, scx).ok() +} + +pub fn method_signature(id: NodeId, + ident: ast::Ident, + m: &ast::MethodSig, + scx: &SaveContext) + -> Option { + make_method_signature(id, ident, m, scx).ok() +} + +pub fn assoc_const_signature(id: NodeId, + ident: ast::Name, + ty: &ast::Ty, + default: Option<&ast::Expr>, + scx: &SaveContext) + -> Option { + make_assoc_const_signature(id, ident, ty, default, scx).ok() +} + +pub fn assoc_type_signature(id: NodeId, + ident: ast::Ident, + bounds: Option<&ast::TyParamBounds>, + default: Option<&ast::Ty>, + scx: &SaveContext) + -> Option { + make_assoc_type_signature(id, ident, bounds, default, scx).ok() +} + +type Result = ::std::result::Result; + +trait Sig { + fn make(&self, offset: usize, id: Option, scx: &SaveContext) -> Result; +} + +fn extend_sig(mut sig: Signature, + text: String, + defs: Vec, + refs: Vec) + -> Signature { + sig.text = text; + sig.defs.extend(defs.into_iter()); + sig.refs.extend(refs.into_iter()); + sig +} + +fn replace_text(mut sig: Signature, text: String) -> Signature { + sig.text = text; + sig +} + +fn merge_sigs(text: String, sigs: Vec) -> Signature { + let mut result = Signature { + text, + defs: vec![], + refs: vec![], + }; + + let (defs, refs): (Vec<_>, Vec<_>) = sigs.into_iter().map(|s| (s.defs, s.refs)).unzip(); + + result.defs.extend(defs.into_iter().flat_map(|ds| ds.into_iter())); + result.refs.extend(refs.into_iter().flat_map(|rs| rs.into_iter())); + + result +} + +fn text_sig(text: String) -> Signature { + Signature { + text: text, + defs: vec![], + refs: vec![], + } +} + +impl Sig for ast::Ty { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let id = Some(self.id); + match self.node { + ast::TyKind::Slice(ref ty) => { + let nested = ty.make(offset + 1, id, scx)?; + let text = format!("[{}]", nested.text); + Ok(replace_text(nested, text)) + } + ast::TyKind::Ptr(ref mt) => { + let prefix = match mt.mutbl { + ast::Mutability::Mutable => "*mut ", + ast::Mutability::Immutable => "*const ", + }; + let nested = mt.ty.make(offset + prefix.len(), id, scx)?; + let text = format!("{}{}", prefix, nested.text); + Ok(replace_text(nested, text)) + } + ast::TyKind::Rptr(ref lifetime, ref mt) => { + let mut prefix = "&".to_owned(); + if let &Some(ref l) = lifetime { + prefix.push_str(&l.ident.to_string()); + prefix.push(' '); + } + if let ast::Mutability::Mutable = mt.mutbl { + prefix.push_str("mut "); + }; + + let nested = mt.ty.make(offset + prefix.len(), id, scx)?; + let text = format!("{}{}", prefix, nested.text); + Ok(replace_text(nested, text)) + } + ast::TyKind::Never => { + Ok(text_sig("!".to_owned())) + }, + ast::TyKind::Tup(ref ts) => { + let mut text = "(".to_owned(); + let mut defs = vec![]; + let mut refs = vec![]; + for t in ts { + let nested = t.make(offset + text.len(), id, scx)?; + text.push_str(&nested.text); + text.push(','); + defs.extend(nested.defs.into_iter()); + refs.extend(nested.refs.into_iter()); + } + text.push(')'); + Ok(Signature { text, defs, refs }) + } + ast::TyKind::Paren(ref ty) => { + let nested = ty.make(offset + 1, id, scx)?; + let text = format!("({})", nested.text); + Ok(replace_text(nested, text)) + } + ast::TyKind::BareFn(ref f) => { + let mut text = String::new(); + if !f.lifetimes.is_empty() { + // FIXME defs, bounds on lifetimes + text.push_str("for<"); + text.push_str(&f.lifetimes.iter().map(|l| + l.lifetime.ident.to_string()).collect::>().join(", ")); + text.push('>'); + } + + if f.unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + if f.abi != ::syntax::abi::Abi::Rust { + text.push_str("extern"); + text.push_str(&f.abi.to_string()); + text.push(' '); + } + text.push_str("fn("); + + let mut defs = vec![]; + let mut refs = vec![]; + for i in &f.decl.inputs { + let nested = i.ty.make(offset + text.len(), Some(i.id), scx)?; + text.push_str(&nested.text); + text.push(','); + defs.extend(nested.defs.into_iter()); + refs.extend(nested.refs.into_iter()); + } + text.push(')'); + if let ast::FunctionRetTy::Ty(ref t) = f.decl.output { + text.push_str(" -> "); + let nested = t.make(offset + text.len(), None, scx)?; + text.push_str(&nested.text); + text.push(','); + defs.extend(nested.defs.into_iter()); + refs.extend(nested.refs.into_iter()); + } + + Ok(Signature { text, defs, refs }) + } + ast::TyKind::Path(None, ref path) => { + path.make(offset, id, scx) + } + ast::TyKind::Path(Some(ref qself), ref path) => { + let nested_ty = qself.ty.make(offset + 1, id, scx)?; + let prefix = if qself.position == 0 { + format!("<{}>::", nested_ty.text) + } else if qself.position == 1 { + let first = pprust::path_segment_to_string(&path.segments[0]); + format!("<{} as {}>::", nested_ty.text, first) + } else { + // FIXME handle path instead of elipses. + format!("<{} as ...>::", nested_ty.text) + }; + + let name = pprust::path_segment_to_string(path.segments.last().ok_or("Bad path")?); + let def = scx.get_path_def(id.ok_or("Missing id for Path")?); + let id = id_from_def_id(def.def_id()); + if path.segments.len() - qself.position == 1 { + let start = offset + prefix.len(); + let end = start + name.len(); + + Ok(Signature { + text: prefix + &name, + defs: vec![], + refs: vec![SigElement { id, start, end }], + }) + } else { + let start = offset + prefix.len() + 5; + let end = start + name.len(); + // FIXME should put the proper path in there, not elipses. + Ok(Signature { + text: prefix + "...::" + &name, + defs: vec![], + refs: vec![SigElement { id, start, end }], + }) + } + } + ast::TyKind::TraitObject(ref bounds) => { + // FIXME recurse into bounds + let nested = pprust::bounds_to_string(bounds); + Ok(text_sig(nested)) + } + ast::TyKind::ImplTrait(ref bounds) => { + // FIXME recurse into bounds + let nested = pprust::bounds_to_string(bounds); + Ok(text_sig(format!("impl {}", nested))) + } + ast::TyKind::Array(ref ty, ref v) => { + let nested_ty = ty.make(offset + 1, id, scx)?; + let expr = pprust::expr_to_string(v).replace('\n', " "); + let text = format!("[{}; {}]", nested_ty.text, expr); + Ok(replace_text(nested_ty, text)) + } + ast::TyKind::Typeof(_) | + ast::TyKind::Infer | + ast::TyKind::Err | + ast::TyKind::ImplicitSelf | + ast::TyKind::Mac(_) => Err("Ty"), + } + } +} + +impl Sig for ast::Item { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let id = Some(self.id); + + match self.node { + ast::ItemKind::Static(ref ty, m, ref expr) => { + let mut text = "static ".to_owned(); + if m == ast::Mutability::Mutable { + text.push_str("mut "); + } + let name = self.ident.to_string(); + let defs = vec![SigElement { + id: id_from_node_id(self.id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }]; + text.push_str(&name); + text.push_str(": "); + + let ty = ty.make(offset + text.len(), id, scx)?; + text.push_str(&ty.text); + text.push_str(" = "); + + let expr = pprust::expr_to_string(expr).replace('\n', " "); + text.push_str(&expr); + text.push(';'); + + Ok(extend_sig(ty, text, defs, vec![])) + } + ast::ItemKind::Const(ref ty, ref expr) => { + let mut text = "const ".to_owned(); + let name = self.ident.to_string(); + let defs = vec![SigElement { + id: id_from_node_id(self.id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }]; + text.push_str(&name); + text.push_str(": "); + + let ty = ty.make(offset + text.len(), id, scx)?; + text.push_str(&ty.text); + text.push_str(" = "); + + let expr = pprust::expr_to_string(expr).replace('\n', " "); + text.push_str(&expr); + text.push(';'); + + Ok(extend_sig(ty, text, defs, vec![])) + } + ast::ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, _) => { + let mut text = String::new(); + if constness.node == ast::Constness::Const { + text.push_str("const "); + } + if unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + if abi != ::syntax::abi::Abi::Rust { + text.push_str("extern"); + text.push_str(&abi.to_string()); + text.push(' '); + } + text.push_str("fn "); + + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + + sig.text.push('('); + for i in &decl.inputs { + // FIXME shoudl descend into patterns to add defs. + sig.text.push_str(&pprust::pat_to_string(&i.pat)); + sig.text.push_str(": "); + let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?; + sig.text.push_str(&nested.text); + sig.text.push(','); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push(')'); + + if let ast::FunctionRetTy::Ty(ref t) = decl.output { + sig.text.push_str(" -> "); + let nested = t.make(offset + sig.text.len(), None, scx)?; + sig.text.push_str(&nested.text); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push_str(" {}"); + + Ok(sig) + } + ast::ItemKind::Mod(ref _mod) => { + let mut text = "mod ".to_owned(); + let name = self.ident.to_string(); + let defs = vec![SigElement { + id: id_from_node_id(self.id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }]; + text.push_str(&name); + // Could be either `mod foo;` or `mod foo { ... }`, but we'll just puck one. + text.push(';'); + + Ok(Signature { + text, + defs, + refs: vec![], + }) + } + ast::ItemKind::Ty(ref ty, ref generics) => { + let text = "type ".to_owned(); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + + sig.text.push_str(" = "); + let ty = ty.make(offset + sig.text.len(), id, scx)?; + sig.text.push_str(&ty.text); + sig.text.push(';'); + + Ok(merge_sigs(sig.text.clone(), vec![sig, ty])) + } + ast::ItemKind::Enum(_, ref generics) => { + let text = "enum ".to_owned(); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + sig.text.push_str(" {}"); + Ok(sig) + } + ast::ItemKind::Struct(_, ref generics) => { + let text = "struct ".to_owned(); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + sig.text.push_str(" {}"); + Ok(sig) + } + ast::ItemKind::Union(_, ref generics) => { + let text = "union ".to_owned(); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + sig.text.push_str(" {}"); + Ok(sig) + } + ast::ItemKind::Trait(unsafety, ref generics, ref bounds, _) => { + let mut text = String::new(); + if unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + text.push_str("trait "); + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + + if !bounds.is_empty() { + sig.text.push_str(": "); + sig.text.push_str(&pprust::bounds_to_string(bounds)); + } + // FIXME where clause + sig.text.push_str(" {}"); + + Ok(sig) + } + ast::ItemKind::DefaultImpl(unsafety, ref trait_ref) => { + let mut text = String::new(); + if unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + text.push_str("impl "); + let trait_sig = trait_ref.path.make(offset + text.len(), id, scx)?; + text.push_str(&trait_sig.text); + text.push_str(" for .. {}"); + Ok(replace_text(trait_sig, text)) + } + ast::ItemKind::Impl(unsafety, + polarity, + defaultness, + ref generics, + ref opt_trait, + ref ty, + _) => { + let mut text = String::new(); + if let ast::Defaultness::Default = defaultness { + text.push_str("default "); + } + if unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + text.push_str("impl"); + + let generics_sig = generics.make(offset + text.len(), id, scx)?; + text.push_str(&generics_sig.text); + + text.push(' '); + + let trait_sig = if let Some(ref t) = *opt_trait { + if polarity == ast::ImplPolarity::Negative { + text.push('!'); + } + let trait_sig = t.path.make(offset + text.len(), id, scx)?; + text.push_str(&trait_sig.text); + text.push_str(" for "); + trait_sig + } else { + text_sig(String::new()) + }; + + let ty_sig = ty.make(offset + text.len(), id, scx)?; + text.push_str(&ty_sig.text); + + text.push_str(" {}"); + + Ok(merge_sigs(text, vec![generics_sig, trait_sig, ty_sig])) + + // FIXME where clause + } + ast::ItemKind::ForeignMod(_) => Err("extern mod"), + ast::ItemKind::GlobalAsm(_) => Err("glboal asm"), + ast::ItemKind::ExternCrate(_) => Err("extern crate"), + // FIXME should implement this (e.g., pub use). + ast::ItemKind::Use(_) => Err("import"), + ast::ItemKind::Mac(..) | + ast::ItemKind::MacroDef(_) => Err("Macro"), + } + } +} + +impl Sig for ast::Path { + fn make(&self, offset: usize, id: Option, scx: &SaveContext) -> Result { + let def = scx.get_path_def(id.ok_or("Missing id for Path")?); + + let (name, start, end) = match def { + Def::Label(..) | + Def::PrimTy(..) | + Def::SelfTy(..) | + Def::Err => { + return Ok(Signature { + text: pprust::path_to_string(self), + defs: vec![], + refs: vec![], + }) + } + Def::AssociatedConst(..) | + Def::Variant(..) | + Def::VariantCtor(..) => { + let len = self.segments.len(); + if len < 2 { + return Err("Bad path"); + } + // FIXME: really we should descend into the generics here and add SigElements for + // them. + // FIXME: would be nice to have a def for the first path segment. + let seg1 = pprust::path_segment_to_string(&self.segments[len - 2]); + let seg2 = pprust::path_segment_to_string(&self.segments[len - 1]); + let start = offset + seg1.len() + 2; + (format!("{}::{}", seg1, seg2), start, start + seg2.len()) + } + _ => { + let name = pprust::path_segment_to_string(self.segments.last().ok_or("Bad path")?); + let end = offset + name.len(); + (name, offset, end) + } + }; + + let id = id_from_def_id(def.def_id()); + Ok(Signature { + text: name, + defs: vec![], + refs: vec![SigElement { id, start, end }], + }) + } +} + +// This does not cover the where clause, which must be processed separately. +impl Sig for ast::Generics { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let total = self.lifetimes.len() + self.ty_params.len(); + if total == 0 { + return Ok(text_sig(String::new())); + } + + let mut text = "<".to_owned(); + + let mut defs = vec![]; + for l in &self.lifetimes { + let mut l_text = l.lifetime.ident.to_string(); + defs.push(SigElement { + id: id_from_node_id(l.lifetime.id, scx), + start: offset + text.len(), + end: offset + text.len() + l_text.len(), + }); + + if !l.bounds.is_empty() { + l_text.push_str(": "); + let bounds = l.bounds.iter().map(|l| { + l.ident.to_string() + }).collect::>().join(" + "); + l_text.push_str(&bounds); + // FIXME add lifetime bounds refs. + } + text.push_str(&l_text); + text.push(','); + } + for t in &self.ty_params { + let mut t_text = t.ident.to_string(); + defs.push(SigElement { + id: id_from_node_id(t.id, scx), + start: offset + text.len(), + end: offset + text.len() + t_text.len(), + }); + + if !t.bounds.is_empty() { + t_text.push_str(": "); + t_text.push_str(&pprust::bounds_to_string(&t.bounds)); + // FIXME descend properly into bounds. + } + text.push_str(&t_text); + text.push(','); + } + + text.push('>'); + Ok(Signature {text, defs, refs: vec![] }) + } +} + +impl Sig for ast::StructField { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let mut text = String::new(); + let mut defs = None; + if let Some(ref ident) = self.ident { + text.push_str(&ident.to_string()); + defs = Some(SigElement { + id: id_from_node_id(self.id, scx), + start: offset, + end: offset + text.len(), + }); + text.push_str(": "); + } + + let mut ty_sig = self.ty.make(offset + text.len(), Some(self.id), scx)?; + text.push_str(&ty_sig.text); + ty_sig.text = text; + ty_sig.defs.extend(defs.into_iter()); + Ok(ty_sig) + } +} + + +impl Sig for ast::Variant_ { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let mut text = self.name.to_string(); + match self.data { + ast::VariantData::Struct(ref fields, id) => { + let name_def = SigElement { + id: id_from_node_id(id, scx), + start: offset, + end: offset + text.len(), + }; + text.push_str(" { "); + let mut defs = vec![name_def]; + let mut refs = vec![]; + for f in fields { + let field_sig = f.make(offset + text.len(), Some(id), scx)?; + text.push_str(&field_sig.text); + text.push_str(", "); + defs.extend(field_sig.defs.into_iter()); + refs.extend(field_sig.refs.into_iter()); + } + text.push('}'); + Ok(Signature { + text, + defs: defs, + refs: refs, + }) + } + ast::VariantData::Tuple(ref fields, id) => { + let name_def = SigElement { + id: id_from_node_id(id, scx), + start: offset, + end: offset + text.len(), + }; + text.push('('); + let mut defs = vec![name_def]; + let mut refs = vec![]; + for f in fields { + let field_sig = f.make(offset + text.len(), Some(id), scx)?; + text.push_str(&field_sig.text); + text.push_str(", "); + defs.extend(field_sig.defs.into_iter()); + refs.extend(field_sig.refs.into_iter()); + } + text.push(')'); + Ok(Signature { + text, + defs: defs, + refs: refs, + }) + } + ast::VariantData::Unit(id) => { + let name_def = SigElement { + id: id_from_node_id(id, scx), + start: offset, + end: offset + text.len(), + }; + Ok(Signature { + text, + defs: vec![name_def], + refs: vec![], + }) + } + } + } +} + +impl Sig for ast::ForeignItem { + fn make(&self, offset: usize, _parent_id: Option, scx: &SaveContext) -> Result { + let id = Some(self.id); + match self.node { + ast::ForeignItemKind::Fn(ref decl, ref generics) => { + let mut text = String::new(); + text.push_str("fn "); + + let mut sig = name_and_generics(text, + offset, + generics, + self.id, + self.ident, + scx)?; + + sig.text.push('('); + for i in &decl.inputs { + // FIXME should descend into patterns to add defs. + sig.text.push_str(&pprust::pat_to_string(&i.pat)); + sig.text.push_str(": "); + let nested = i.ty.make(offset + sig.text.len(), Some(i.id), scx)?; + sig.text.push_str(&nested.text); + sig.text.push(','); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push(')'); + + if let ast::FunctionRetTy::Ty(ref t) = decl.output { + sig.text.push_str(" -> "); + let nested = t.make(offset + sig.text.len(), None, scx)?; + sig.text.push_str(&nested.text); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push(';'); + + Ok(sig) + } + ast::ForeignItemKind::Static(ref ty, m) => { + let mut text = "static ".to_owned(); + if m { + text.push_str("mut "); + } + let name = self.ident.to_string(); + let defs = vec![SigElement { + id: id_from_node_id(self.id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }]; + text.push_str(&name); + text.push_str(": "); + + let ty_sig = ty.make(offset + text.len(), id, scx)?; + text.push(';'); + + Ok(extend_sig(ty_sig, text, defs, vec![])) + } + } + } +} + +fn name_and_generics(mut text: String, + offset: usize, + generics: &ast::Generics, + id: NodeId, + name: ast::Ident, + scx: &SaveContext) + -> Result { + let name = name.to_string(); + let def = SigElement { + id: id_from_node_id(id, scx), + start: offset + text.len(), + end: offset + text.len() + name.len(), + }; + text.push_str(&name); + let generics: Signature = generics.make(offset + text.len(), Some(id), scx)?; + // FIXME where clause + let text = format!("{}{}", text, generics.text); + Ok(extend_sig(generics, text, vec![def], vec![])) +} + + +fn make_assoc_type_signature(id: NodeId, + ident: ast::Ident, + bounds: Option<&ast::TyParamBounds>, + default: Option<&ast::Ty>, + scx: &SaveContext) + -> Result { + let mut text = "type ".to_owned(); + let name = ident.to_string(); + let mut defs = vec![SigElement { + id: id_from_node_id(id, scx), + start: text.len(), + end: text.len() + name.len(), + }]; + let mut refs = vec![]; + text.push_str(&name); + if let Some(bounds) = bounds { + text.push_str(": "); + // FIXME should descend into bounds + text.push_str(&pprust::bounds_to_string(bounds)); + } + if let Some(default) = default { + text.push_str(" = "); + let ty_sig = default.make(text.len(), Some(id), scx)?; + text.push_str(&ty_sig.text); + defs.extend(ty_sig.defs.into_iter()); + refs.extend(ty_sig.refs.into_iter()); + } + text.push(';'); + Ok(Signature { text, defs, refs }) +} + +fn make_assoc_const_signature(id: NodeId, + ident: ast::Name, + ty: &ast::Ty, + default: Option<&ast::Expr>, + scx: &SaveContext) + -> Result { + let mut text = "const ".to_owned(); + let name = ident.to_string(); + let mut defs = vec![SigElement { + id: id_from_node_id(id, scx), + start: text.len(), + end: text.len() + name.len(), + }]; + let mut refs = vec![]; + text.push_str(&name); + text.push_str(": "); + + let ty_sig = ty.make(text.len(), Some(id), scx)?; + text.push_str(&ty_sig.text); + defs.extend(ty_sig.defs.into_iter()); + refs.extend(ty_sig.refs.into_iter()); + + if let Some(default) = default { + text.push_str(" = "); + text.push_str(&pprust::expr_to_string(default)); + } + text.push(';'); + Ok(Signature { text, defs, refs }) +} + +fn make_method_signature(id: NodeId, + ident: ast::Ident, + m: &ast::MethodSig, + scx: &SaveContext) + -> Result { + // FIXME code dup with function signature + let mut text = String::new(); + if m.constness.node == ast::Constness::Const { + text.push_str("const "); + } + if m.unsafety == ast::Unsafety::Unsafe { + text.push_str("unsafe "); + } + if m.abi != ::syntax::abi::Abi::Rust { + text.push_str("extern"); + text.push_str(&m.abi.to_string()); + text.push(' '); + } + text.push_str("fn "); + + let mut sig = name_and_generics(text, + 0, + &m.generics, + id, + ident, + scx)?; + + sig.text.push('('); + for i in &m.decl.inputs { + // FIXME shoudl descend into patterns to add defs. + sig.text.push_str(&pprust::pat_to_string(&i.pat)); + sig.text.push_str(": "); + let nested = i.ty.make(sig.text.len(), Some(i.id), scx)?; + sig.text.push_str(&nested.text); + sig.text.push(','); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push(')'); + + if let ast::FunctionRetTy::Ty(ref t) = m.decl.output { + sig.text.push_str(" -> "); + let nested = t.make(sig.text.len(), None, scx)?; + sig.text.push_str(&nested.text); + sig.defs.extend(nested.defs.into_iter()); + sig.refs.extend(nested.refs.into_iter()); + } + sig.text.push_str(" {}"); + + Ok(sig) +} diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 073ededcb0ce7..34cda433d5250 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -370,6 +370,10 @@ pub fn path_to_string(p: &ast::Path) -> String { to_string(|s| s.print_path(p, false, 0, false)) } +pub fn path_segment_to_string(p: &ast::PathSegment) -> String { + to_string(|s| s.print_path_segment(p, false)) +} + pub fn ident_to_string(id: ast::Ident) -> String { to_string(|s| s.print_ident(id)) } @@ -2359,18 +2363,27 @@ impl<'a> State<'a> { if i > 0 { word(&mut self.s, "::")? } - if segment.identifier.name != keywords::CrateRoot.name() && - segment.identifier.name != "$crate" { - self.print_ident(segment.identifier)?; - if let Some(ref parameters) = segment.parameters { - self.print_path_parameters(parameters, colons_before_params)?; - } - } + self.print_path_segment(segment, colons_before_params)?; } Ok(()) } + fn print_path_segment(&mut self, + segment: &ast::PathSegment, + colons_before_params: bool) + -> io::Result<()> + { + if segment.identifier.name != keywords::CrateRoot.name() && + segment.identifier.name != "$crate" { + self.print_ident(segment.identifier)?; + if let Some(ref parameters) = segment.parameters { + self.print_path_parameters(parameters, colons_before_params)?; + } + } + Ok(()) + } + fn print_qpath(&mut self, path: &ast::Path, qself: &ast::QSelf, diff --git a/src/tools/rls b/src/tools/rls index bfe80cfa8db75..0d0f3baad02d6 160000 --- a/src/tools/rls +++ b/src/tools/rls @@ -1 +1 @@ -Subproject commit bfe80cfa8db75500e67ca8762465d27662674637 +Subproject commit 0d0f3baad02d65d96befbb90e77bf8a326dd14f5