mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-13 09:05:00 +00:00
e4e5db4e42
This currently creates a field which is always false on GenericParamDefKind for future use when consts are permitted to have defaults Update const_generics:default locations Previously just ignored them, now actually do something about them. Fix using type check instead of value Add parsing This adds all the necessary changes to lower const-generics defaults from parsing. Change P<Expr> to AnonConst This matches the arguments passed to instantiations of const generics, and makes it specific to just anonymous constants. Attempt to fix lowering bugs
935 lines
34 KiB
Rust
935 lines
34 KiB
Rust
// 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 omission (FIXME).
|
|
//
|
|
// FIXME where clauses need implementing, defs/refs in generics are mostly missing.
|
|
|
|
use crate::{id_from_def_id, id_from_hir_id, SaveContext};
|
|
|
|
use rls_data::{SigElement, Signature};
|
|
|
|
use rustc_ast::Mutability;
|
|
use rustc_hir as hir;
|
|
use rustc_hir::def::{DefKind, Res};
|
|
use rustc_hir_pretty::id_to_string;
|
|
use rustc_hir_pretty::{bounds_to_string, path_segment_to_string, path_to_string, ty_to_string};
|
|
use rustc_span::symbol::{Ident, Symbol};
|
|
|
|
pub fn item_signature(item: &hir::Item<'_>, scx: &SaveContext<'_>) -> Option<Signature> {
|
|
if !scx.config.signatures {
|
|
return None;
|
|
}
|
|
item.make(0, None, scx).ok()
|
|
}
|
|
|
|
pub fn foreign_item_signature(
|
|
item: &hir::ForeignItem<'_>,
|
|
scx: &SaveContext<'_>,
|
|
) -> Option<Signature> {
|
|
if !scx.config.signatures {
|
|
return None;
|
|
}
|
|
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: &hir::FieldDef<'_>, scx: &SaveContext<'_>) -> Option<Signature> {
|
|
if !scx.config.signatures {
|
|
return None;
|
|
}
|
|
field.make(0, None, scx).ok()
|
|
}
|
|
|
|
/// Does not include a trailing comma.
|
|
pub fn variant_signature(variant: &hir::Variant<'_>, scx: &SaveContext<'_>) -> Option<Signature> {
|
|
if !scx.config.signatures {
|
|
return None;
|
|
}
|
|
variant.make(0, None, scx).ok()
|
|
}
|
|
|
|
pub fn method_signature(
|
|
id: hir::HirId,
|
|
ident: Ident,
|
|
generics: &hir::Generics<'_>,
|
|
m: &hir::FnSig<'_>,
|
|
scx: &SaveContext<'_>,
|
|
) -> Option<Signature> {
|
|
if !scx.config.signatures {
|
|
return None;
|
|
}
|
|
make_method_signature(id, ident, generics, m, scx).ok()
|
|
}
|
|
|
|
pub fn assoc_const_signature(
|
|
id: hir::HirId,
|
|
ident: Symbol,
|
|
ty: &hir::Ty<'_>,
|
|
default: Option<&hir::Expr<'_>>,
|
|
scx: &SaveContext<'_>,
|
|
) -> Option<Signature> {
|
|
if !scx.config.signatures {
|
|
return None;
|
|
}
|
|
make_assoc_const_signature(id, ident, ty, default, scx).ok()
|
|
}
|
|
|
|
pub fn assoc_type_signature(
|
|
id: hir::HirId,
|
|
ident: Ident,
|
|
bounds: Option<hir::GenericBounds<'_>>,
|
|
default: Option<&hir::Ty<'_>>,
|
|
scx: &SaveContext<'_>,
|
|
) -> Option<Signature> {
|
|
if !scx.config.signatures {
|
|
return None;
|
|
}
|
|
make_assoc_type_signature(id, ident, bounds, default, scx).ok()
|
|
}
|
|
|
|
type Result = std::result::Result<Signature, &'static str>;
|
|
|
|
trait Sig {
|
|
fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result;
|
|
}
|
|
|
|
fn extend_sig(
|
|
mut sig: Signature,
|
|
text: String,
|
|
defs: Vec<SigElement>,
|
|
refs: Vec<SigElement>,
|
|
) -> 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>) -> 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, defs: vec![], refs: vec![] }
|
|
}
|
|
|
|
impl<'hir> Sig for hir::Ty<'hir> {
|
|
fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
|
let id = Some(self.hir_id);
|
|
match self.kind {
|
|
hir::TyKind::Slice(ref ty) => {
|
|
let nested = ty.make(offset + 1, id, scx)?;
|
|
let text = format!("[{}]", nested.text);
|
|
Ok(replace_text(nested, text))
|
|
}
|
|
hir::TyKind::Ptr(ref mt) => {
|
|
let prefix = match mt.mutbl {
|
|
hir::Mutability::Mut => "*mut ",
|
|
hir::Mutability::Not => "*const ",
|
|
};
|
|
let nested = mt.ty.make(offset + prefix.len(), id, scx)?;
|
|
let text = format!("{}{}", prefix, nested.text);
|
|
Ok(replace_text(nested, text))
|
|
}
|
|
hir::TyKind::Rptr(ref lifetime, ref mt) => {
|
|
let mut prefix = "&".to_owned();
|
|
prefix.push_str(&lifetime.name.ident().to_string());
|
|
prefix.push(' ');
|
|
if let hir::Mutability::Mut = 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))
|
|
}
|
|
hir::TyKind::Never => Ok(text_sig("!".to_owned())),
|
|
hir::TyKind::Tup(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 })
|
|
}
|
|
hir::TyKind::BareFn(ref f) => {
|
|
let mut text = String::new();
|
|
if !f.generic_params.is_empty() {
|
|
// FIXME defs, bounds on lifetimes
|
|
text.push_str("for<");
|
|
text.push_str(
|
|
&f.generic_params
|
|
.iter()
|
|
.filter_map(|param| match param.kind {
|
|
hir::GenericParamKind::Lifetime { .. } => {
|
|
Some(param.name.ident().to_string())
|
|
}
|
|
_ => None,
|
|
})
|
|
.collect::<Vec<_>>()
|
|
.join(", "),
|
|
);
|
|
text.push('>');
|
|
}
|
|
|
|
if let hir::Unsafety::Unsafe = f.unsafety {
|
|
text.push_str("unsafe ");
|
|
}
|
|
text.push_str("fn(");
|
|
|
|
let mut defs = vec![];
|
|
let mut refs = vec![];
|
|
for i in f.decl.inputs {
|
|
let nested = i.make(offset + text.len(), Some(i.hir_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 hir::FnRetTy::Return(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 })
|
|
}
|
|
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.make(offset, id, scx),
|
|
hir::TyKind::Path(hir::QPath::Resolved(Some(ref qself), ref path)) => {
|
|
let nested_ty = qself.make(offset + 1, id, scx)?;
|
|
let prefix = format!(
|
|
"<{} as {}>::",
|
|
nested_ty.text,
|
|
path_segment_to_string(&path.segments[0])
|
|
);
|
|
|
|
let name = path_segment_to_string(path.segments.last().ok_or("Bad path")?);
|
|
let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
|
|
let id = id_from_def_id(res.def_id());
|
|
if path.segments.len() == 2 {
|
|
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 ellipsis.
|
|
Ok(Signature {
|
|
text: prefix + "...::" + &name,
|
|
defs: vec![],
|
|
refs: vec![SigElement { id, start, end }],
|
|
})
|
|
}
|
|
}
|
|
hir::TyKind::Path(hir::QPath::TypeRelative(ty, segment)) => {
|
|
let nested_ty = ty.make(offset + 1, id, scx)?;
|
|
let prefix = format!("<{}>::", nested_ty.text);
|
|
|
|
let name = path_segment_to_string(segment);
|
|
let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
|
|
let id = id_from_def_id(res.def_id());
|
|
|
|
let start = offset + prefix.len();
|
|
let end = start + name.len();
|
|
Ok(Signature {
|
|
text: prefix + &name,
|
|
defs: vec![],
|
|
refs: vec![SigElement { id, start, end }],
|
|
})
|
|
}
|
|
hir::TyKind::Path(hir::QPath::LangItem(lang_item, _)) => {
|
|
Ok(text_sig(format!("#[lang = \"{}\"]", lang_item.name())))
|
|
}
|
|
hir::TyKind::TraitObject(bounds, ..) => {
|
|
// FIXME recurse into bounds
|
|
let bounds: Vec<hir::GenericBound<'_>> = bounds
|
|
.iter()
|
|
.map(|hir::PolyTraitRef { bound_generic_params, trait_ref, span }| {
|
|
hir::GenericBound::Trait(
|
|
hir::PolyTraitRef {
|
|
bound_generic_params,
|
|
trait_ref: hir::TraitRef {
|
|
path: trait_ref.path,
|
|
hir_ref_id: trait_ref.hir_ref_id,
|
|
},
|
|
span: *span,
|
|
},
|
|
hir::TraitBoundModifier::None,
|
|
)
|
|
})
|
|
.collect();
|
|
let nested = bounds_to_string(&bounds);
|
|
Ok(text_sig(nested))
|
|
}
|
|
hir::TyKind::Array(ref ty, ref anon_const) => {
|
|
let nested_ty = ty.make(offset + 1, id, scx)?;
|
|
let expr = id_to_string(&scx.tcx.hir(), anon_const.body.hir_id).replace('\n', " ");
|
|
let text = format!("[{}; {}]", nested_ty.text, expr);
|
|
Ok(replace_text(nested_ty, text))
|
|
}
|
|
hir::TyKind::OpaqueDef(item_id, _) => {
|
|
let item = scx.tcx.hir().item(item_id);
|
|
item.make(offset, Some(item_id.hir_id()), scx)
|
|
}
|
|
hir::TyKind::Typeof(_) | hir::TyKind::Infer | hir::TyKind::Err => Err("Ty"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'hir> Sig for hir::Item<'hir> {
|
|
fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
|
let id = Some(self.hir_id());
|
|
|
|
match self.kind {
|
|
hir::ItemKind::Static(ref ty, m, ref body) => {
|
|
let mut text = "static ".to_owned();
|
|
if m == hir::Mutability::Mut {
|
|
text.push_str("mut ");
|
|
}
|
|
let name = self.ident.to_string();
|
|
let defs = vec![SigElement {
|
|
id: id_from_def_id(self.def_id.to_def_id()),
|
|
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 = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " ");
|
|
text.push_str(&expr);
|
|
|
|
text.push(';');
|
|
|
|
Ok(extend_sig(ty, text, defs, vec![]))
|
|
}
|
|
hir::ItemKind::Const(ref ty, ref body) => {
|
|
let mut text = "const ".to_owned();
|
|
let name = self.ident.to_string();
|
|
let defs = vec![SigElement {
|
|
id: id_from_def_id(self.def_id.to_def_id()),
|
|
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 = id_to_string(&scx.tcx.hir(), body.hir_id).replace('\n', " ");
|
|
text.push_str(&expr);
|
|
|
|
text.push(';');
|
|
|
|
Ok(extend_sig(ty, text, defs, vec![]))
|
|
}
|
|
hir::ItemKind::Fn(hir::FnSig { ref decl, header, span: _ }, ref generics, _) => {
|
|
let mut text = String::new();
|
|
if let hir::Constness::Const = header.constness {
|
|
text.push_str("const ");
|
|
}
|
|
if hir::IsAsync::Async == header.asyncness {
|
|
text.push_str("async ");
|
|
}
|
|
if let hir::Unsafety::Unsafe = header.unsafety {
|
|
text.push_str("unsafe ");
|
|
}
|
|
text.push_str("fn ");
|
|
|
|
let mut sig =
|
|
name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
|
|
|
|
sig.text.push('(');
|
|
for i in decl.inputs {
|
|
// FIXME should descend into patterns to add defs.
|
|
sig.text.push_str(": ");
|
|
let nested = i.make(offset + sig.text.len(), Some(i.hir_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 hir::FnRetTy::Return(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)
|
|
}
|
|
hir::ItemKind::Mod(ref _mod) => {
|
|
let mut text = "mod ".to_owned();
|
|
let name = self.ident.to_string();
|
|
let defs = vec![SigElement {
|
|
id: id_from_def_id(self.def_id.to_def_id()),
|
|
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 pick one.
|
|
text.push(';');
|
|
|
|
Ok(Signature { text, defs, refs: vec![] })
|
|
}
|
|
hir::ItemKind::TyAlias(ref ty, ref generics) => {
|
|
let text = "type ".to_owned();
|
|
let mut sig =
|
|
name_and_generics(text, offset, generics, self.hir_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]))
|
|
}
|
|
hir::ItemKind::Enum(_, ref generics) => {
|
|
let text = "enum ".to_owned();
|
|
let mut sig =
|
|
name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
|
|
sig.text.push_str(" {}");
|
|
Ok(sig)
|
|
}
|
|
hir::ItemKind::Struct(_, ref generics) => {
|
|
let text = "struct ".to_owned();
|
|
let mut sig =
|
|
name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
|
|
sig.text.push_str(" {}");
|
|
Ok(sig)
|
|
}
|
|
hir::ItemKind::Union(_, ref generics) => {
|
|
let text = "union ".to_owned();
|
|
let mut sig =
|
|
name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
|
|
sig.text.push_str(" {}");
|
|
Ok(sig)
|
|
}
|
|
hir::ItemKind::Trait(is_auto, unsafety, ref generics, bounds, _) => {
|
|
let mut text = String::new();
|
|
|
|
if is_auto == hir::IsAuto::Yes {
|
|
text.push_str("auto ");
|
|
}
|
|
|
|
if let hir::Unsafety::Unsafe = unsafety {
|
|
text.push_str("unsafe ");
|
|
}
|
|
text.push_str("trait ");
|
|
let mut sig =
|
|
name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
|
|
|
|
if !bounds.is_empty() {
|
|
sig.text.push_str(": ");
|
|
sig.text.push_str(&bounds_to_string(bounds));
|
|
}
|
|
// FIXME where clause
|
|
sig.text.push_str(" {}");
|
|
|
|
Ok(sig)
|
|
}
|
|
hir::ItemKind::TraitAlias(ref generics, bounds) => {
|
|
let mut text = String::new();
|
|
text.push_str("trait ");
|
|
let mut sig =
|
|
name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
|
|
|
|
if !bounds.is_empty() {
|
|
sig.text.push_str(" = ");
|
|
sig.text.push_str(&bounds_to_string(bounds));
|
|
}
|
|
// FIXME where clause
|
|
sig.text.push(';');
|
|
|
|
Ok(sig)
|
|
}
|
|
hir::ItemKind::Impl(hir::Impl {
|
|
unsafety,
|
|
polarity,
|
|
defaultness,
|
|
defaultness_span: _,
|
|
constness,
|
|
ref generics,
|
|
ref of_trait,
|
|
ref self_ty,
|
|
items: _,
|
|
}) => {
|
|
let mut text = String::new();
|
|
if let hir::Defaultness::Default { .. } = defaultness {
|
|
text.push_str("default ");
|
|
}
|
|
if let hir::Unsafety::Unsafe = unsafety {
|
|
text.push_str("unsafe ");
|
|
}
|
|
text.push_str("impl");
|
|
if let hir::Constness::Const = constness {
|
|
text.push_str(" const");
|
|
}
|
|
|
|
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) = *of_trait {
|
|
if let hir::ImplPolarity::Negative(_) = polarity {
|
|
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 = self_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
|
|
}
|
|
hir::ItemKind::ForeignMod { .. } => Err("extern mod"),
|
|
hir::ItemKind::GlobalAsm(_) => Err("global asm"),
|
|
hir::ItemKind::ExternCrate(_) => Err("extern crate"),
|
|
hir::ItemKind::OpaqueTy(..) => Err("opaque type"),
|
|
// FIXME should implement this (e.g., pub use).
|
|
hir::ItemKind::Use(..) => Err("import"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'hir> Sig for hir::Path<'hir> {
|
|
fn make(&self, offset: usize, id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
|
let res = scx.get_path_res(id.ok_or("Missing id for Path")?);
|
|
|
|
let (name, start, end) = match res {
|
|
Res::PrimTy(..) | Res::SelfTy(..) | Res::Err => {
|
|
return Ok(Signature { text: path_to_string(self), defs: vec![], refs: vec![] });
|
|
}
|
|
Res::Def(DefKind::AssocConst | DefKind::Variant | DefKind::Ctor(..), _) => {
|
|
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 = path_segment_to_string(&self.segments[len - 2]);
|
|
let seg2 = path_segment_to_string(&self.segments[len - 1]);
|
|
let start = offset + seg1.len() + 2;
|
|
(format!("{}::{}", seg1, seg2), start, start + seg2.len())
|
|
}
|
|
_ => {
|
|
let name = 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(res.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<'hir> Sig for hir::Generics<'hir> {
|
|
fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
|
if self.params.is_empty() {
|
|
return Ok(text_sig(String::new()));
|
|
}
|
|
|
|
let mut text = "<".to_owned();
|
|
|
|
let mut defs = Vec::with_capacity(self.params.len());
|
|
for param in self.params {
|
|
let mut param_text = String::new();
|
|
if let hir::GenericParamKind::Const { .. } = param.kind {
|
|
param_text.push_str("const ");
|
|
}
|
|
param_text.push_str(¶m.name.ident().as_str());
|
|
defs.push(SigElement {
|
|
id: id_from_hir_id(param.hir_id, scx),
|
|
start: offset + text.len(),
|
|
end: offset + text.len() + param_text.as_str().len(),
|
|
});
|
|
if let hir::GenericParamKind::Const { ref ty, default } = param.kind {
|
|
param_text.push_str(": ");
|
|
param_text.push_str(&ty_to_string(&ty));
|
|
if let Some(default) = default {
|
|
param_text.push_str(" = ");
|
|
param_text.push_str(&id_to_string(&scx.tcx.hir(), default.hir_id));
|
|
}
|
|
}
|
|
if !param.bounds.is_empty() {
|
|
param_text.push_str(": ");
|
|
match param.kind {
|
|
hir::GenericParamKind::Lifetime { .. } => {
|
|
let bounds = param
|
|
.bounds
|
|
.iter()
|
|
.map(|bound| match bound {
|
|
hir::GenericBound::Outlives(lt) => lt.name.ident().to_string(),
|
|
_ => panic!(),
|
|
})
|
|
.collect::<Vec<_>>()
|
|
.join(" + ");
|
|
param_text.push_str(&bounds);
|
|
// FIXME add lifetime bounds refs.
|
|
}
|
|
hir::GenericParamKind::Type { .. } => {
|
|
param_text.push_str(&bounds_to_string(param.bounds));
|
|
// FIXME descend properly into bounds.
|
|
}
|
|
hir::GenericParamKind::Const { .. } => {
|
|
// Const generics cannot contain bounds.
|
|
}
|
|
}
|
|
}
|
|
text.push_str(¶m_text);
|
|
text.push(',');
|
|
}
|
|
|
|
text.push('>');
|
|
Ok(Signature { text, defs, refs: vec![] })
|
|
}
|
|
}
|
|
|
|
impl<'hir> Sig for hir::FieldDef<'hir> {
|
|
fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
|
let mut text = String::new();
|
|
|
|
text.push_str(&self.ident.to_string());
|
|
let defs = Some(SigElement {
|
|
id: id_from_hir_id(self.hir_id, scx),
|
|
start: offset,
|
|
end: offset + text.len(),
|
|
});
|
|
text.push_str(": ");
|
|
|
|
let mut ty_sig = self.ty.make(offset + text.len(), Some(self.hir_id), scx)?;
|
|
text.push_str(&ty_sig.text);
|
|
ty_sig.text = text;
|
|
ty_sig.defs.extend(defs.into_iter());
|
|
Ok(ty_sig)
|
|
}
|
|
}
|
|
|
|
impl<'hir> Sig for hir::Variant<'hir> {
|
|
fn make(&self, offset: usize, parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
|
let mut text = self.ident.to_string();
|
|
match self.data {
|
|
hir::VariantData::Struct(fields, r) => {
|
|
let id = parent_id.ok_or("Missing id for Variant's parent")?;
|
|
let name_def = SigElement {
|
|
id: id_from_hir_id(id, scx),
|
|
start: offset,
|
|
end: offset + text.len(),
|
|
};
|
|
text.push_str(" { ");
|
|
let mut defs = vec![name_def];
|
|
let mut refs = vec![];
|
|
if r {
|
|
text.push_str("/* parse error */ ");
|
|
} else {
|
|
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, refs })
|
|
}
|
|
hir::VariantData::Tuple(fields, id) => {
|
|
let name_def = SigElement {
|
|
id: id_from_hir_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, refs })
|
|
}
|
|
hir::VariantData::Unit(id) => {
|
|
let name_def = SigElement {
|
|
id: id_from_hir_id(id, scx),
|
|
start: offset,
|
|
end: offset + text.len(),
|
|
};
|
|
Ok(Signature { text, defs: vec![name_def], refs: vec![] })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'hir> Sig for hir::ForeignItem<'hir> {
|
|
fn make(&self, offset: usize, _parent_id: Option<hir::HirId>, scx: &SaveContext<'_>) -> Result {
|
|
let id = Some(self.hir_id());
|
|
match self.kind {
|
|
hir::ForeignItemKind::Fn(decl, _, ref generics) => {
|
|
let mut text = String::new();
|
|
text.push_str("fn ");
|
|
|
|
let mut sig =
|
|
name_and_generics(text, offset, generics, self.hir_id(), self.ident, scx)?;
|
|
|
|
sig.text.push('(');
|
|
for i in decl.inputs {
|
|
sig.text.push_str(": ");
|
|
let nested = i.make(offset + sig.text.len(), Some(i.hir_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 hir::FnRetTy::Return(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)
|
|
}
|
|
hir::ForeignItemKind::Static(ref ty, m) => {
|
|
let mut text = "static ".to_owned();
|
|
if m == Mutability::Mut {
|
|
text.push_str("mut ");
|
|
}
|
|
let name = self.ident.to_string();
|
|
let defs = vec![SigElement {
|
|
id: id_from_def_id(self.def_id.to_def_id()),
|
|
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![]))
|
|
}
|
|
hir::ForeignItemKind::Type => {
|
|
let mut text = "type ".to_owned();
|
|
let name = self.ident.to_string();
|
|
let defs = vec![SigElement {
|
|
id: id_from_def_id(self.def_id.to_def_id()),
|
|
start: offset + text.len(),
|
|
end: offset + text.len() + name.len(),
|
|
}];
|
|
text.push_str(&name);
|
|
text.push(';');
|
|
|
|
Ok(Signature { text, defs, refs: vec![] })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn name_and_generics(
|
|
mut text: String,
|
|
offset: usize,
|
|
generics: &hir::Generics<'_>,
|
|
id: hir::HirId,
|
|
name: Ident,
|
|
scx: &SaveContext<'_>,
|
|
) -> Result {
|
|
let name = name.to_string();
|
|
let def = SigElement {
|
|
id: id_from_hir_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: hir::HirId,
|
|
ident: Ident,
|
|
bounds: Option<hir::GenericBounds<'_>>,
|
|
default: Option<&hir::Ty<'_>>,
|
|
scx: &SaveContext<'_>,
|
|
) -> Result {
|
|
let mut text = "type ".to_owned();
|
|
let name = ident.to_string();
|
|
let mut defs = vec![SigElement {
|
|
id: id_from_hir_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(&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: hir::HirId,
|
|
ident: Symbol,
|
|
ty: &hir::Ty<'_>,
|
|
default: Option<&hir::Expr<'_>>,
|
|
scx: &SaveContext<'_>,
|
|
) -> Result {
|
|
let mut text = "const ".to_owned();
|
|
let name = ident.to_string();
|
|
let mut defs = vec![SigElement {
|
|
id: id_from_hir_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(&id_to_string(&scx.tcx.hir(), default.hir_id));
|
|
}
|
|
text.push(';');
|
|
Ok(Signature { text, defs, refs })
|
|
}
|
|
|
|
fn make_method_signature(
|
|
id: hir::HirId,
|
|
ident: Ident,
|
|
generics: &hir::Generics<'_>,
|
|
m: &hir::FnSig<'_>,
|
|
scx: &SaveContext<'_>,
|
|
) -> Result {
|
|
// FIXME code dup with function signature
|
|
let mut text = String::new();
|
|
if let hir::Constness::Const = m.header.constness {
|
|
text.push_str("const ");
|
|
}
|
|
if hir::IsAsync::Async == m.header.asyncness {
|
|
text.push_str("async ");
|
|
}
|
|
if let hir::Unsafety::Unsafe = m.header.unsafety {
|
|
text.push_str("unsafe ");
|
|
}
|
|
text.push_str("fn ");
|
|
|
|
let mut sig = name_and_generics(text, 0, generics, id, ident, scx)?;
|
|
|
|
sig.text.push('(');
|
|
for i in m.decl.inputs {
|
|
sig.text.push_str(": ");
|
|
let nested = i.make(sig.text.len(), Some(i.hir_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 hir::FnRetTy::Return(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)
|
|
}
|