mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-21 11:23:03 +00:00
7900: show function params in completion detail r=matklad a=JoshMcguigan This resolves #7842 by updating the detail for function completions from `-> T` to `fn(T, U) -> V`. I added an expicit unit test for this, `ide_completion::render::fn_detail_includes_args_and_return_type`, which passes. Lots of other unit tests fail (~60 of them) due to this change, although I believe the failures are purely cosmetic (they were testing the exact format of this output). I'm happy to go update those tests, but before I do that I'd like to make sure this is in fact the format we want for the detail? edit - I realized `UPDATE_EXPECT=1 cargo test` automatically updates `expect!` tests. Big 👍 to whoever worked on that! So I'll go ahead and update all these tests soon. But I still would like to confirm `fn(T, U) -> V` is the desired content in the `detail` field. 8000: Use hir formatter for hover text r=matklad a=oxalica Fix #2765 , (should) fix #4665 Co-authored-by: Josh Mcguigan <joshmcg88@gmail.com> Co-authored-by: oxalica <oxalicc@pm.me>
This commit is contained in:
commit
1a82af3527
441
crates/hir/src/display.rs
Normal file
441
crates/hir/src/display.rs
Normal file
@ -0,0 +1,441 @@
|
||||
//! HirDisplay implementations for various hir types.
|
||||
use hir_def::{
|
||||
adt::VariantData,
|
||||
generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
AdtId, GenericDefId,
|
||||
};
|
||||
use hir_ty::display::{
|
||||
write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
|
||||
HirFormatter,
|
||||
};
|
||||
use syntax::ast::{self, NameOwner};
|
||||
|
||||
use crate::{
|
||||
Const, ConstParam, Enum, Field, Function, HasVisibility, Module, Static, Struct, Substs, Trait,
|
||||
Type, TypeAlias, TypeParam, Union, Variant,
|
||||
};
|
||||
|
||||
impl HirDisplay for Function {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
let data = f.db.function_data(self.id);
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
let qual = &data.qualifier;
|
||||
if qual.is_default {
|
||||
write!(f, "default ")?;
|
||||
}
|
||||
if qual.is_const {
|
||||
write!(f, "const ")?;
|
||||
}
|
||||
if qual.is_async {
|
||||
write!(f, "async ")?;
|
||||
}
|
||||
if qual.is_unsafe {
|
||||
write!(f, "unsafe ")?;
|
||||
}
|
||||
if let Some(abi) = &qual.abi {
|
||||
// FIXME: String escape?
|
||||
write!(f, "extern \"{}\" ", abi)?;
|
||||
}
|
||||
write!(f, "fn {}", data.name)?;
|
||||
|
||||
write_generic_params(GenericDefId::FunctionId(self.id), f)?;
|
||||
|
||||
write!(f, "(")?;
|
||||
|
||||
let write_self_param = |ty: &TypeRef, f: &mut HirFormatter| match ty {
|
||||
TypeRef::Path(p) if p.is_self_type() => write!(f, "self"),
|
||||
TypeRef::Reference(inner, lifetime, mut_) if matches!(&**inner,TypeRef::Path(p) if p.is_self_type()) =>
|
||||
{
|
||||
write!(f, "&")?;
|
||||
if let Some(lifetime) = lifetime {
|
||||
write!(f, "{} ", lifetime.name)?;
|
||||
}
|
||||
if let hir_def::type_ref::Mutability::Mut = mut_ {
|
||||
write!(f, "mut ")?;
|
||||
}
|
||||
write!(f, "self")
|
||||
}
|
||||
_ => {
|
||||
write!(f, "self: ")?;
|
||||
ty.hir_fmt(f)
|
||||
}
|
||||
};
|
||||
|
||||
let mut first = true;
|
||||
for (param, type_ref) in self.assoc_fn_params(f.db).into_iter().zip(&data.params) {
|
||||
if !first {
|
||||
write!(f, ", ")?;
|
||||
} else {
|
||||
first = false;
|
||||
if data.has_self_param {
|
||||
write_self_param(type_ref, f)?;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
match param.pattern_source(f.db) {
|
||||
Some(ast::Pat::IdentPat(p)) if p.name().is_some() => {
|
||||
write!(f, "{}: ", p.name().unwrap())?
|
||||
}
|
||||
_ => write!(f, "_: ")?,
|
||||
}
|
||||
// FIXME: Use resolved `param.ty` or raw `type_ref`?
|
||||
// The former will ignore lifetime arguments currently.
|
||||
type_ref.hir_fmt(f)?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
|
||||
// `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
|
||||
// Use ugly pattern match to strip the Future trait.
|
||||
// Better way?
|
||||
let ret_type = if !qual.is_async {
|
||||
&data.ret_type
|
||||
} else {
|
||||
match &data.ret_type {
|
||||
TypeRef::ImplTrait(bounds) => match &bounds[0] {
|
||||
TypeBound::Path(path) => {
|
||||
path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
|
||||
[0]
|
||||
.type_ref
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
}
|
||||
_ => panic!("Async fn ret_type should be impl Future"),
|
||||
},
|
||||
_ => panic!("Async fn ret_type should be impl Future"),
|
||||
}
|
||||
};
|
||||
|
||||
match ret_type {
|
||||
TypeRef::Tuple(tup) if tup.is_empty() => {}
|
||||
ty => {
|
||||
write!(f, " -> ")?;
|
||||
ty.hir_fmt(f)?;
|
||||
}
|
||||
}
|
||||
|
||||
write_where_clause(GenericDefId::FunctionId(self.id), f)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Struct {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
write!(f, "struct ")?;
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
|
||||
write_generic_params(def_id, f)?;
|
||||
write_where_clause(def_id, f)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Enum {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
write!(f, "enum ")?;
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
|
||||
write_generic_params(def_id, f)?;
|
||||
write_where_clause(def_id, f)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Union {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
write!(f, "union ")?;
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
|
||||
write_generic_params(def_id, f)?;
|
||||
write_where_clause(def_id, f)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Field {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
|
||||
write!(f, "{}: ", self.name(f.db))?;
|
||||
self.signature_ty(f.db).hir_fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Variant {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
let data = self.variant_data(f.db);
|
||||
match &*data {
|
||||
VariantData::Unit => {}
|
||||
VariantData::Tuple(fields) => {
|
||||
write!(f, "(")?;
|
||||
let mut first = true;
|
||||
for (_, field) in fields.iter() {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
// Enum variant fields must be pub.
|
||||
field.type_ref.hir_fmt(f)?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
}
|
||||
VariantData::Record(fields) => {
|
||||
write!(f, " {{")?;
|
||||
let mut first = true;
|
||||
for (_, field) in fields.iter() {
|
||||
if first {
|
||||
first = false;
|
||||
write!(f, " ")?;
|
||||
} else {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
// Enum variant fields must be pub.
|
||||
write!(f, "{}: ", field.name)?;
|
||||
field.type_ref.hir_fmt(f)?;
|
||||
}
|
||||
write!(f, " }}")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Type {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
self.ty.value.hir_fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for TypeParam {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
let bounds = f.db.generic_predicates_for_param(self.id);
|
||||
let substs = Substs::type_params(f.db, self.id.parent);
|
||||
let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
|
||||
if !(predicates.is_empty() || f.omit_verbose_types()) {
|
||||
write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for ConstParam {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write!(f, "const {}: ", self.name(f.db))?;
|
||||
self.ty(f.db).hir_fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
let params = f.db.generic_params(def);
|
||||
if params.lifetimes.is_empty()
|
||||
&& params.consts.is_empty()
|
||||
&& params
|
||||
.types
|
||||
.iter()
|
||||
.all(|(_, param)| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
write!(f, "<")?;
|
||||
|
||||
let mut first = true;
|
||||
let mut delim = |f: &mut HirFormatter| {
|
||||
if first {
|
||||
first = false;
|
||||
Ok(())
|
||||
} else {
|
||||
write!(f, ", ")
|
||||
}
|
||||
};
|
||||
for (_, lifetime) in params.lifetimes.iter() {
|
||||
delim(f)?;
|
||||
write!(f, "{}", lifetime.name)?;
|
||||
}
|
||||
for (_, ty) in params.types.iter() {
|
||||
if ty.provenance != TypeParamProvenance::TypeParamList {
|
||||
continue;
|
||||
}
|
||||
if let Some(name) = &ty.name {
|
||||
delim(f)?;
|
||||
write!(f, "{}", name)?;
|
||||
if let Some(default) = &ty.default {
|
||||
write!(f, " = ")?;
|
||||
default.hir_fmt(f)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (_, konst) in params.consts.iter() {
|
||||
delim(f)?;
|
||||
write!(f, "const {}: ", konst.name)?;
|
||||
konst.ty.hir_fmt(f)?;
|
||||
}
|
||||
|
||||
write!(f, ">")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
let params = f.db.generic_params(def);
|
||||
if params.where_predicates.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target {
|
||||
WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
|
||||
WherePredicateTypeTarget::TypeParam(id) => match ¶ms.types[*id].name {
|
||||
Some(name) => write!(f, "{}", name),
|
||||
None => write!(f, "{{unnamed}}"),
|
||||
},
|
||||
};
|
||||
|
||||
write!(f, "\nwhere")?;
|
||||
|
||||
for (pred_idx, pred) in params.where_predicates.iter().enumerate() {
|
||||
let prev_pred =
|
||||
if pred_idx == 0 { None } else { Some(¶ms.where_predicates[pred_idx - 1]) };
|
||||
|
||||
let new_predicate = |f: &mut HirFormatter| {
|
||||
write!(f, "{}", if pred_idx == 0 { "\n " } else { ",\n " })
|
||||
};
|
||||
|
||||
match pred {
|
||||
WherePredicate::TypeBound { target, bound } => {
|
||||
if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target)
|
||||
{
|
||||
write!(f, " + ")?;
|
||||
} else {
|
||||
new_predicate(f)?;
|
||||
write_target(target, f)?;
|
||||
write!(f, ": ")?;
|
||||
}
|
||||
bound.hir_fmt(f)?;
|
||||
}
|
||||
WherePredicate::Lifetime { target, bound } => {
|
||||
if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target)
|
||||
{
|
||||
write!(f, " + {}", bound.name)?;
|
||||
} else {
|
||||
new_predicate(f)?;
|
||||
write!(f, "{}: {}", target.name, bound.name)?;
|
||||
}
|
||||
}
|
||||
WherePredicate::ForLifetime { lifetimes, target, bound } => {
|
||||
if matches!(
|
||||
prev_pred,
|
||||
Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. })
|
||||
if lifetimes_ == lifetimes && target_ == target,
|
||||
) {
|
||||
write!(f, " + ")?;
|
||||
} else {
|
||||
new_predicate(f)?;
|
||||
write!(f, "for<")?;
|
||||
for (idx, lifetime) in lifetimes.iter().enumerate() {
|
||||
if idx != 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{}", lifetime)?;
|
||||
}
|
||||
write!(f, "> ")?;
|
||||
write_target(target, f)?;
|
||||
write!(f, ": ")?;
|
||||
}
|
||||
bound.hir_fmt(f)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// End of final predicate. There must be at least one predicate here.
|
||||
write!(f, ",")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl HirDisplay for Const {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
let data = f.db.const_data(self.id);
|
||||
write!(f, "const ")?;
|
||||
match &data.name {
|
||||
Some(name) => write!(f, "{}: ", name)?,
|
||||
None => write!(f, "_: ")?,
|
||||
}
|
||||
data.type_ref.hir_fmt(f)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Static {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
let data = f.db.static_data(self.id);
|
||||
write!(f, "static ")?;
|
||||
if data.mutable {
|
||||
write!(f, "mut ")?;
|
||||
}
|
||||
match &data.name {
|
||||
Some(name) => write!(f, "{}: ", name)?,
|
||||
None => write!(f, "_: ")?,
|
||||
}
|
||||
data.type_ref.hir_fmt(f)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Trait {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
let data = f.db.trait_data(self.id);
|
||||
if data.is_unsafe {
|
||||
write!(f, "unsafe ")?;
|
||||
}
|
||||
if data.is_auto {
|
||||
write!(f, "auto ")?;
|
||||
}
|
||||
write!(f, "trait {}", data.name)?;
|
||||
let def_id = GenericDefId::TraitId(self.id);
|
||||
write_generic_params(def_id, f)?;
|
||||
if !data.bounds.is_empty() {
|
||||
write!(f, ": ")?;
|
||||
f.write_joined(&*data.bounds, " + ")?;
|
||||
}
|
||||
write_where_clause(def_id, f)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for TypeAlias {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
|
||||
let data = f.db.type_alias_data(self.id);
|
||||
write!(f, "type {}", data.name)?;
|
||||
if !data.bounds.is_empty() {
|
||||
write!(f, ": ")?;
|
||||
f.write_joined(&data.bounds, " + ")?;
|
||||
}
|
||||
if let Some(ty) = &data.type_ref {
|
||||
write!(f, " = ")?;
|
||||
ty.hir_fmt(f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Module {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
// FIXME: Module doesn't have visibility saved in data.
|
||||
match self.name(f.db) {
|
||||
Some(name) => write!(f, "mod {}", name),
|
||||
None if self.crate_root(f.db) == *self => match self.krate().display_name(f.db) {
|
||||
Some(name) => write!(f, "extern crate {}", name),
|
||||
None => write!(f, "extern crate {{unknown}}"),
|
||||
},
|
||||
None => write!(f, "mod {{unnamed}}"),
|
||||
}
|
||||
}
|
||||
}
|
@ -29,6 +29,8 @@ mod has_source;
|
||||
pub mod diagnostics;
|
||||
pub mod db;
|
||||
|
||||
mod display;
|
||||
|
||||
use std::{iter, sync::Arc};
|
||||
|
||||
use arrayvec::ArrayVec;
|
||||
@ -50,7 +52,6 @@ use hir_def::{
|
||||
use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind};
|
||||
use hir_ty::{
|
||||
autoderef,
|
||||
display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter},
|
||||
method_resolution::{self, TyFingerprint},
|
||||
primitive::UintTy,
|
||||
to_assoc_type_id,
|
||||
@ -572,6 +573,12 @@ impl Struct {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Struct {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
db.struct_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Union {
|
||||
pub(crate) id: UnionId,
|
||||
@ -604,6 +611,12 @@ impl Union {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Union {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
db.union_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Enum {
|
||||
pub(crate) id: EnumId,
|
||||
@ -631,6 +644,12 @@ impl Enum {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Enum {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
db.enum_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Variant {
|
||||
pub(crate) parent: Enum,
|
||||
@ -822,7 +841,8 @@ impl Function {
|
||||
db.function_data(self.id)
|
||||
.params
|
||||
.iter()
|
||||
.map(|type_ref| {
|
||||
.enumerate()
|
||||
.map(|(idx, type_ref)| {
|
||||
let ty = Type {
|
||||
krate,
|
||||
ty: InEnvironment {
|
||||
@ -830,7 +850,7 @@ impl Function {
|
||||
environment: environment.clone(),
|
||||
},
|
||||
};
|
||||
Param { ty }
|
||||
Param { func: self, ty, idx }
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
@ -844,7 +864,7 @@ impl Function {
|
||||
}
|
||||
|
||||
pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
|
||||
db.function_data(self.id).is_unsafe
|
||||
db.function_data(self.id).qualifier.is_unsafe
|
||||
}
|
||||
|
||||
pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
|
||||
@ -893,6 +913,9 @@ impl From<hir_ty::Mutability> for Access {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Param {
|
||||
func: Function,
|
||||
/// The index in parameter list, including self parameter.
|
||||
idx: usize,
|
||||
ty: Type,
|
||||
}
|
||||
|
||||
@ -900,6 +923,15 @@ impl Param {
|
||||
pub fn ty(&self) -> &Type {
|
||||
&self.ty
|
||||
}
|
||||
|
||||
pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
|
||||
let params = self.func.source(db)?.value.param_list()?;
|
||||
if params.self_param().is_some() {
|
||||
params.params().nth(self.idx.checked_sub(1)?)?.pat()
|
||||
} else {
|
||||
params.params().nth(self.idx)?.pat()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@ -922,6 +954,14 @@ impl SelfParam {
|
||||
})
|
||||
.unwrap_or(Access::Owned)
|
||||
}
|
||||
|
||||
pub fn display(self, db: &dyn HirDatabase) -> &'static str {
|
||||
match self.access(db) {
|
||||
Access::Shared => "&self",
|
||||
Access::Exclusive => "&mut self",
|
||||
Access::Owned => "self",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Function {
|
||||
@ -949,6 +989,10 @@ impl Const {
|
||||
pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
|
||||
db.const_data(self.id).name.clone()
|
||||
}
|
||||
|
||||
pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRef {
|
||||
db.const_data(self.id).type_ref.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Const {
|
||||
@ -982,6 +1026,12 @@ impl Static {
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Static {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
db.static_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct Trait {
|
||||
pub(crate) id: TraitId,
|
||||
@ -1001,7 +1051,13 @@ impl Trait {
|
||||
}
|
||||
|
||||
pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
|
||||
db.trait_data(self.id).auto
|
||||
db.trait_data(self.id).is_auto
|
||||
}
|
||||
}
|
||||
|
||||
impl HasVisibility for Trait {
|
||||
fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
|
||||
db.trait_data(self.id).visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1413,19 +1469,6 @@ impl TypeParam {
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for TypeParam {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
write!(f, "{}", self.name(f.db))?;
|
||||
let bounds = f.db.generic_predicates_for_param(self.id);
|
||||
let substs = Substs::type_params(f.db, self.id.parent);
|
||||
let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
|
||||
if !(predicates.is_empty() || f.omit_verbose_types()) {
|
||||
write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct LifetimeParam {
|
||||
pub(crate) id: LifetimeParamId,
|
||||
@ -2059,12 +2102,6 @@ impl Type {
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Type {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
self.ty.value.hir_fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: closures
|
||||
#[derive(Debug)]
|
||||
pub struct Callable {
|
||||
|
@ -31,12 +31,14 @@ pub struct StructData {
|
||||
pub name: Name,
|
||||
pub variant_data: Arc<VariantData>,
|
||||
pub repr: Option<ReprKind>,
|
||||
pub visibility: RawVisibility,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnumData {
|
||||
pub name: Name,
|
||||
pub variants: Arena<EnumVariantData>,
|
||||
pub visibility: RawVisibility,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@ -102,6 +104,7 @@ impl StructData {
|
||||
name: strukt.name.clone(),
|
||||
variant_data: Arc::new(variant_data),
|
||||
repr,
|
||||
visibility: item_tree[strukt.visibility].clone(),
|
||||
})
|
||||
}
|
||||
pub(crate) fn union_data_query(db: &dyn DefDatabase, id: UnionId) -> Arc<StructData> {
|
||||
@ -118,6 +121,7 @@ impl StructData {
|
||||
name: union.name.clone(),
|
||||
variant_data: Arc::new(variant_data),
|
||||
repr,
|
||||
visibility: item_tree[union.visibility].clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -150,7 +154,11 @@ impl EnumData {
|
||||
}
|
||||
}
|
||||
|
||||
Arc::new(EnumData { name: enum_.name.clone(), variants })
|
||||
Arc::new(EnumData {
|
||||
name: enum_.name.clone(),
|
||||
variants,
|
||||
visibility: item_tree[enum_.visibility].clone(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn variant(&self, name: &Name) -> Option<LocalEnumVariantId> {
|
||||
|
@ -9,7 +9,7 @@ use crate::{
|
||||
attr::Attrs,
|
||||
body::Expander,
|
||||
db::DefDatabase,
|
||||
item_tree::{AssocItem, ItemTreeId, ModItem},
|
||||
item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem},
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
visibility::RawVisibility,
|
||||
AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
|
||||
@ -26,9 +26,9 @@ pub struct FunctionData {
|
||||
/// can be called as a method.
|
||||
pub has_self_param: bool,
|
||||
pub has_body: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub qualifier: FunctionQualifier,
|
||||
pub is_in_extern_block: bool,
|
||||
pub is_varargs: bool,
|
||||
pub is_extern: bool,
|
||||
pub visibility: RawVisibility,
|
||||
}
|
||||
|
||||
@ -46,9 +46,9 @@ impl FunctionData {
|
||||
attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
|
||||
has_self_param: func.has_self_param,
|
||||
has_body: func.has_body,
|
||||
is_unsafe: func.is_unsafe,
|
||||
qualifier: func.qualifier.clone(),
|
||||
is_in_extern_block: func.is_in_extern_block,
|
||||
is_varargs: func.is_varargs,
|
||||
is_extern: func.is_extern,
|
||||
visibility: item_tree[func.visibility].clone(),
|
||||
})
|
||||
}
|
||||
@ -87,7 +87,10 @@ impl TypeAliasData {
|
||||
pub struct TraitData {
|
||||
pub name: Name,
|
||||
pub items: Vec<(Name, AssocItemId)>,
|
||||
pub auto: bool,
|
||||
pub is_auto: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub visibility: RawVisibility,
|
||||
pub bounds: Box<[TypeBound]>,
|
||||
}
|
||||
|
||||
impl TraitData {
|
||||
@ -96,10 +99,13 @@ impl TraitData {
|
||||
let item_tree = db.item_tree(tr_loc.id.file_id);
|
||||
let tr_def = &item_tree[tr_loc.id.value];
|
||||
let name = tr_def.name.clone();
|
||||
let auto = tr_def.auto;
|
||||
let is_auto = tr_def.is_auto;
|
||||
let is_unsafe = tr_def.is_unsafe;
|
||||
let module_id = tr_loc.container;
|
||||
let container = AssocContainerId::TraitId(tr);
|
||||
let mut expander = Expander::new(db, tr_loc.id.file_id, module_id);
|
||||
let visibility = item_tree[tr_def.visibility].clone();
|
||||
let bounds = tr_def.bounds.clone();
|
||||
|
||||
let items = collect_items(
|
||||
db,
|
||||
@ -111,7 +117,7 @@ impl TraitData {
|
||||
100,
|
||||
);
|
||||
|
||||
Arc::new(TraitData { name, items, auto })
|
||||
Arc::new(TraitData { name, items, is_auto, is_unsafe, visibility, bounds })
|
||||
}
|
||||
|
||||
pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ {
|
||||
|
@ -24,7 +24,7 @@ use la_arena::{Arena, Idx, RawIdx};
|
||||
use profile::Count;
|
||||
use rustc_hash::FxHashMap;
|
||||
use smallvec::SmallVec;
|
||||
use syntax::{ast, match_ast, SyntaxKind};
|
||||
use syntax::{ast, match_ast, SmolStr, SyntaxKind};
|
||||
|
||||
use crate::{
|
||||
attr::{Attrs, RawAttrs},
|
||||
@ -556,16 +556,25 @@ pub struct Function {
|
||||
pub generic_params: GenericParamsId,
|
||||
pub has_self_param: bool,
|
||||
pub has_body: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub qualifier: FunctionQualifier,
|
||||
/// Whether the function is located in an `extern` block (*not* whether it is an
|
||||
/// `extern "abi" fn`).
|
||||
pub is_extern: bool,
|
||||
pub is_in_extern_block: bool,
|
||||
pub params: Box<[Idx<TypeRef>]>,
|
||||
pub is_varargs: bool,
|
||||
pub ret_type: Idx<TypeRef>,
|
||||
pub ast_id: FileAstId<ast::Fn>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct FunctionQualifier {
|
||||
pub is_default: bool,
|
||||
pub is_const: bool,
|
||||
pub is_async: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub abi: Option<SmolStr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Struct {
|
||||
pub name: Name,
|
||||
@ -629,7 +638,9 @@ pub struct Trait {
|
||||
pub name: Name,
|
||||
pub visibility: RawVisibilityId,
|
||||
pub generic_params: GenericParamsId,
|
||||
pub auto: bool,
|
||||
pub is_auto: bool,
|
||||
pub is_unsafe: bool,
|
||||
pub bounds: Box<[TypeBound]>,
|
||||
pub items: Box<[AssocItem]>,
|
||||
pub ast_id: FileAstId<ast::Trait>,
|
||||
}
|
||||
|
@ -391,14 +391,33 @@ impl Ctx {
|
||||
let has_body = func.body().is_some();
|
||||
|
||||
let ast_id = self.source_ast_id_map.ast_id(func);
|
||||
let qualifier = FunctionQualifier {
|
||||
is_default: func.default_token().is_some(),
|
||||
is_const: func.const_token().is_some(),
|
||||
is_async: func.async_token().is_some(),
|
||||
is_unsafe: func.unsafe_token().is_some(),
|
||||
abi: func.abi().map(|abi| {
|
||||
// FIXME: Abi::abi() -> Option<SyntaxToken>?
|
||||
match abi.syntax().last_token() {
|
||||
Some(tok) if tok.kind() == SyntaxKind::STRING => {
|
||||
// FIXME: Better way to unescape?
|
||||
tok.text().trim_matches('"').into()
|
||||
}
|
||||
_ => {
|
||||
// `extern` default to be `extern "C"`.
|
||||
"C".into()
|
||||
}
|
||||
}
|
||||
}),
|
||||
};
|
||||
let mut res = Function {
|
||||
name,
|
||||
visibility,
|
||||
generic_params: GenericParamsId::EMPTY,
|
||||
has_self_param,
|
||||
has_body,
|
||||
is_unsafe: func.unsafe_token().is_some(),
|
||||
is_extern: false,
|
||||
qualifier,
|
||||
is_in_extern_block: false,
|
||||
params,
|
||||
is_varargs,
|
||||
ret_type,
|
||||
@ -481,7 +500,9 @@ impl Ctx {
|
||||
let visibility = self.lower_visibility(trait_def);
|
||||
let generic_params =
|
||||
self.lower_generic_params_and_inner_items(GenericsOwner::Trait(trait_def), trait_def);
|
||||
let auto = trait_def.auto_token().is_some();
|
||||
let is_auto = trait_def.auto_token().is_some();
|
||||
let is_unsafe = trait_def.unsafe_token().is_some();
|
||||
let bounds = self.lower_type_bounds(trait_def);
|
||||
let items = trait_def.assoc_item_list().map(|list| {
|
||||
self.with_inherited_visibility(visibility, |this| {
|
||||
list.assoc_items()
|
||||
@ -501,7 +522,9 @@ impl Ctx {
|
||||
name,
|
||||
visibility,
|
||||
generic_params,
|
||||
auto,
|
||||
is_auto,
|
||||
is_unsafe,
|
||||
bounds: bounds.into(),
|
||||
items: items.unwrap_or_default(),
|
||||
ast_id,
|
||||
};
|
||||
@ -608,8 +631,8 @@ impl Ctx {
|
||||
ast::ExternItem::Fn(ast) => {
|
||||
let func_id = self.lower_function(&ast)?;
|
||||
let func = &mut self.data().functions[func_id.index];
|
||||
func.is_unsafe = is_intrinsic_fn_unsafe(&func.name);
|
||||
func.is_extern = true;
|
||||
func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name);
|
||||
func.is_in_extern_block = true;
|
||||
func_id.into()
|
||||
}
|
||||
ast::ExternItem::Static(ast) => {
|
||||
|
@ -9,7 +9,10 @@ use std::{
|
||||
|
||||
use crate::{body::LowerCtx, type_ref::LifetimeRef};
|
||||
use base_db::CrateId;
|
||||
use hir_expand::{hygiene::Hygiene, name::Name};
|
||||
use hir_expand::{
|
||||
hygiene::Hygiene,
|
||||
name::{name, Name},
|
||||
};
|
||||
use syntax::ast;
|
||||
|
||||
use crate::{
|
||||
@ -209,6 +212,12 @@ impl Path {
|
||||
};
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn is_self_type(&self) -> bool {
|
||||
self.type_anchor.is_none()
|
||||
&& self.generic_args == &[None]
|
||||
&& self.mod_path.as_ident() == Some(&name!(Self))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -91,7 +91,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
|
||||
|
||||
fn validate_func(&mut self, func: FunctionId) {
|
||||
let data = self.db.function_data(func);
|
||||
if data.is_extern {
|
||||
if data.is_in_extern_block {
|
||||
cov_mark::hit!(extern_func_incorrect_case_ignored);
|
||||
return;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> {
|
||||
let def = self.owner.into();
|
||||
let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
|
||||
let is_unsafe = match self.owner {
|
||||
DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe,
|
||||
DefWithBodyId::FunctionId(it) => db.function_data(it).qualifier.is_unsafe,
|
||||
DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
|
||||
};
|
||||
if is_unsafe
|
||||
@ -86,7 +86,7 @@ fn walk_unsafe(
|
||||
match expr {
|
||||
&Expr::Call { callee, .. } => {
|
||||
if let Some(func) = infer[callee].as_fn_def(db) {
|
||||
if db.function_data(func).is_unsafe {
|
||||
if db.function_data(func).qualifier.is_unsafe {
|
||||
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||
}
|
||||
}
|
||||
@ -103,7 +103,7 @@ fn walk_unsafe(
|
||||
Expr::MethodCall { .. } => {
|
||||
if infer
|
||||
.method_resolution(current)
|
||||
.map(|func| db.function_data(func).is_unsafe)
|
||||
.map(|func| db.function_data(func).qualifier.is_unsafe)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||
|
@ -5,7 +5,13 @@ use std::{borrow::Cow, fmt};
|
||||
use arrayvec::ArrayVec;
|
||||
use chalk_ir::Mutability;
|
||||
use hir_def::{
|
||||
db::DefDatabase, find_path, generics::TypeParamProvenance, item_scope::ItemInNs,
|
||||
db::DefDatabase,
|
||||
find_path,
|
||||
generics::TypeParamProvenance,
|
||||
item_scope::ItemInNs,
|
||||
path::{GenericArg, Path, PathKind},
|
||||
type_ref::{TypeBound, TypeRef},
|
||||
visibility::Visibility,
|
||||
AssocContainerId, Lookup, ModuleId, TraitId,
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
@ -232,7 +238,7 @@ where
|
||||
|
||||
const TYPE_HINT_TRUNCATION: &str = "…";
|
||||
|
||||
impl HirDisplay for &Ty {
|
||||
impl<T: HirDisplay> HirDisplay for &'_ T {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
HirDisplay::hir_fmt(*self, f)
|
||||
}
|
||||
@ -761,12 +767,6 @@ impl HirDisplay for TraitRef {
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for &GenericPredicate {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
HirDisplay::hir_fmt(*self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for GenericPredicate {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
if f.should_truncate() {
|
||||
@ -825,3 +825,190 @@ impl HirDisplay for Obligation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_visibility(
|
||||
module_id: ModuleId,
|
||||
vis: Visibility,
|
||||
f: &mut HirFormatter,
|
||||
) -> Result<(), HirDisplayError> {
|
||||
match vis {
|
||||
Visibility::Public => write!(f, "pub "),
|
||||
Visibility::Module(vis_id) => {
|
||||
let def_map = module_id.def_map(f.db.upcast());
|
||||
let root_module_id = def_map.module_id(def_map.root());
|
||||
if vis_id == module_id {
|
||||
// pub(self) or omitted
|
||||
Ok(())
|
||||
} else if root_module_id == vis_id {
|
||||
write!(f, "pub(crate) ")
|
||||
} else if module_id.containing_module(f.db.upcast()) == Some(vis_id) {
|
||||
write!(f, "pub(super) ")
|
||||
} else {
|
||||
write!(f, "pub(in ...) ")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for TypeRef {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
match self {
|
||||
TypeRef::Never => write!(f, "!")?,
|
||||
TypeRef::Placeholder => write!(f, "_")?,
|
||||
TypeRef::Tuple(elems) => {
|
||||
write!(f, "(")?;
|
||||
f.write_joined(elems, ", ")?;
|
||||
if elems.len() == 1 {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
}
|
||||
TypeRef::Path(path) => path.hir_fmt(f)?,
|
||||
TypeRef::RawPtr(inner, mutability) => {
|
||||
let mutability = match mutability {
|
||||
hir_def::type_ref::Mutability::Shared => "*const ",
|
||||
hir_def::type_ref::Mutability::Mut => "*mut ",
|
||||
};
|
||||
write!(f, "{}", mutability)?;
|
||||
inner.hir_fmt(f)?;
|
||||
}
|
||||
TypeRef::Reference(inner, lifetime, mutability) => {
|
||||
let mutability = match mutability {
|
||||
hir_def::type_ref::Mutability::Shared => "",
|
||||
hir_def::type_ref::Mutability::Mut => "mut ",
|
||||
};
|
||||
write!(f, "&")?;
|
||||
if let Some(lifetime) = lifetime {
|
||||
write!(f, "{} ", lifetime.name)?;
|
||||
}
|
||||
write!(f, "{}", mutability)?;
|
||||
inner.hir_fmt(f)?;
|
||||
}
|
||||
TypeRef::Array(inner) => {
|
||||
write!(f, "[")?;
|
||||
inner.hir_fmt(f)?;
|
||||
// FIXME: Array length?
|
||||
write!(f, "; _]")?;
|
||||
}
|
||||
TypeRef::Slice(inner) => {
|
||||
write!(f, "[")?;
|
||||
inner.hir_fmt(f)?;
|
||||
write!(f, "]")?;
|
||||
}
|
||||
TypeRef::Fn(tys, is_varargs) => {
|
||||
// FIXME: Function pointer qualifiers.
|
||||
write!(f, "fn(")?;
|
||||
f.write_joined(&tys[..tys.len() - 1], ", ")?;
|
||||
if *is_varargs {
|
||||
write!(f, "{}...", if tys.len() == 1 { "" } else { ", " })?;
|
||||
}
|
||||
write!(f, ")")?;
|
||||
let ret_ty = tys.last().unwrap();
|
||||
match ret_ty {
|
||||
TypeRef::Tuple(tup) if tup.is_empty() => {}
|
||||
_ => {
|
||||
write!(f, " -> ")?;
|
||||
ret_ty.hir_fmt(f)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
TypeRef::ImplTrait(bounds) => {
|
||||
write!(f, "impl ")?;
|
||||
f.write_joined(bounds, " + ")?;
|
||||
}
|
||||
TypeRef::DynTrait(bounds) => {
|
||||
write!(f, "dyn ")?;
|
||||
f.write_joined(bounds, " + ")?;
|
||||
}
|
||||
TypeRef::Error => write!(f, "{{error}}")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for TypeBound {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
match self {
|
||||
TypeBound::Path(path) => path.hir_fmt(f),
|
||||
TypeBound::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
|
||||
TypeBound::Error => write!(f, "{{error}}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for Path {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
match (self.type_anchor(), self.kind()) {
|
||||
(Some(anchor), _) => {
|
||||
write!(f, "<")?;
|
||||
anchor.hir_fmt(f)?;
|
||||
write!(f, ">")?;
|
||||
}
|
||||
(_, PathKind::Plain) => {}
|
||||
(_, PathKind::Abs) => write!(f, "::")?,
|
||||
(_, PathKind::Crate) => write!(f, "crate")?,
|
||||
(_, PathKind::Super(0)) => write!(f, "self")?,
|
||||
(_, PathKind::Super(n)) => {
|
||||
write!(f, "super")?;
|
||||
for _ in 0..*n {
|
||||
write!(f, "::super")?;
|
||||
}
|
||||
}
|
||||
(_, PathKind::DollarCrate(_)) => write!(f, "{{extern_crate}}")?,
|
||||
}
|
||||
|
||||
for (seg_idx, segment) in self.segments().iter().enumerate() {
|
||||
if seg_idx != 0 {
|
||||
write!(f, "::")?;
|
||||
}
|
||||
write!(f, "{}", segment.name)?;
|
||||
if let Some(generic_args) = segment.args_and_bindings {
|
||||
// We should be in type context, so format as `Foo<Bar>` instead of `Foo::<Bar>`.
|
||||
// Do we actually format expressions?
|
||||
write!(f, "<")?;
|
||||
let mut first = true;
|
||||
for arg in &generic_args.args {
|
||||
if first {
|
||||
first = false;
|
||||
if generic_args.has_self_type {
|
||||
// FIXME: Convert to `<Ty as Trait>` form.
|
||||
write!(f, "Self = ")?;
|
||||
}
|
||||
} else {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
arg.hir_fmt(f)?;
|
||||
}
|
||||
for binding in &generic_args.bindings {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
write!(f, "{}", binding.name)?;
|
||||
match &binding.type_ref {
|
||||
Some(ty) => {
|
||||
write!(f, " = ")?;
|
||||
ty.hir_fmt(f)?
|
||||
}
|
||||
None => {
|
||||
write!(f, ": ")?;
|
||||
f.write_joined(&binding.bounds, " + ")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
write!(f, ">")?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl HirDisplay for GenericArg {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
|
||||
match self {
|
||||
GenericArg::Type(ty) => ty.hir_fmt(f),
|
||||
GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ pub(crate) fn trait_datum_query(
|
||||
let generic_params = generics(db.upcast(), trait_.into());
|
||||
let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST);
|
||||
let flags = rust_ir::TraitFlags {
|
||||
auto: trait_data.auto,
|
||||
auto: trait_data.is_auto,
|
||||
upstream: trait_.lookup(db.upcast()).container.krate() != krate,
|
||||
non_enumerable: true,
|
||||
coinductive: false, // only relevant for Chalk testing
|
||||
|
@ -5,6 +5,5 @@ pub(crate) mod navigation_target;
|
||||
mod short_label;
|
||||
|
||||
pub(crate) use navigation_target::{ToNav, TryToNav};
|
||||
pub(crate) use short_label::ShortLabel;
|
||||
|
||||
pub(crate) use syntax::display::{function_declaration, macro_label};
|
||||
|
@ -3,7 +3,9 @@
|
||||
use std::fmt;
|
||||
|
||||
use either::Either;
|
||||
use hir::{AssocItem, Documentation, FieldSource, HasAttrs, HasSource, InFile, ModuleSource};
|
||||
use hir::{
|
||||
AssocItem, Documentation, FieldSource, HasAttrs, HasSource, HirDisplay, InFile, ModuleSource,
|
||||
};
|
||||
use ide_db::{
|
||||
base_db::{FileId, FileRange, SourceDatabase},
|
||||
symbol_index::FileSymbolKind,
|
||||
@ -98,7 +100,7 @@ impl NavigationTarget {
|
||||
SymbolKind::Module,
|
||||
);
|
||||
res.docs = module.attrs(db).docs();
|
||||
res.description = src.value.short_label();
|
||||
res.description = Some(module.display(db).to_string());
|
||||
return res;
|
||||
}
|
||||
module.to_nav(db)
|
||||
@ -251,8 +253,8 @@ impl ToNavFromAst for hir::Trait {
|
||||
|
||||
impl<D> TryToNav for D
|
||||
where
|
||||
D: HasSource + ToNavFromAst + Copy + HasAttrs,
|
||||
D::Ast: ast::NameOwner + ShortLabel,
|
||||
D: HasSource + ToNavFromAst + Copy + HasAttrs + HirDisplay,
|
||||
D::Ast: ast::NameOwner,
|
||||
{
|
||||
fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
|
||||
let src = self.source(db)?;
|
||||
@ -262,7 +264,7 @@ where
|
||||
D::KIND,
|
||||
);
|
||||
res.docs = self.docs(db);
|
||||
res.description = src.value.short_label();
|
||||
res.description = Some(self.display(db).to_string());
|
||||
Some(res)
|
||||
}
|
||||
}
|
||||
@ -317,7 +319,7 @@ impl TryToNav for hir::Field {
|
||||
let mut res =
|
||||
NavigationTarget::from_named(db, src.with_value(it), SymbolKind::Field);
|
||||
res.docs = self.docs(db);
|
||||
res.description = it.short_label();
|
||||
res.description = Some(self.display(db).to_string());
|
||||
res
|
||||
}
|
||||
FieldSource::Pos(it) => {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use either::Either;
|
||||
use hir::{
|
||||
Adt, AsAssocItem, AssocItemContainer, FieldSource, GenericParam, HasAttrs, HasSource,
|
||||
HirDisplay, Module, ModuleDef, ModuleSource, Semantics,
|
||||
Adt, AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, Module,
|
||||
ModuleDef, Semantics,
|
||||
};
|
||||
use ide_db::{
|
||||
base_db::SourceDatabase,
|
||||
@ -14,7 +14,7 @@ use stdx::format_to;
|
||||
use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
|
||||
|
||||
use crate::{
|
||||
display::{macro_label, ShortLabel, TryToNav},
|
||||
display::{macro_label, TryToNav},
|
||||
doc_links::{remove_links, rewrite_links},
|
||||
markdown_remove::remove_markdown,
|
||||
markup::Markup,
|
||||
@ -335,34 +335,18 @@ fn hover_for_definition(
|
||||
let label = macro_label(&it.source(db)?.value);
|
||||
from_def_source_labeled(db, it, Some(label), mod_path)
|
||||
}
|
||||
Definition::Field(def) => {
|
||||
let src = def.source(db)?.value;
|
||||
if let FieldSource::Named(it) = src {
|
||||
from_def_source_labeled(db, def, it.short_label(), mod_path)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
Definition::Field(def) => from_hir_fmt(db, def, mod_path),
|
||||
Definition::ModuleDef(it) => match it {
|
||||
ModuleDef::Module(it) => from_def_source_labeled(
|
||||
db,
|
||||
it,
|
||||
match it.definition_source(db).value {
|
||||
ModuleSource::Module(it) => it.short_label(),
|
||||
ModuleSource::SourceFile(it) => it.short_label(),
|
||||
ModuleSource::BlockExpr(it) => it.short_label(),
|
||||
},
|
||||
mod_path,
|
||||
),
|
||||
ModuleDef::Function(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Adt(Adt::Struct(it)) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Adt(Adt::Union(it)) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Adt(Adt::Enum(it)) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Variant(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Const(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Static(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Trait(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::TypeAlias(it) => from_def_source(db, it, mod_path),
|
||||
ModuleDef::Module(it) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::Function(it) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::Adt(Adt::Struct(it)) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::Adt(Adt::Union(it)) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::Adt(Adt::Enum(it)) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::Variant(it) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::Const(it) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::Static(it) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::Trait(it) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::TypeAlias(it) => from_hir_fmt(db, it, mod_path),
|
||||
ModuleDef::BuiltinType(it) => famous_defs
|
||||
.and_then(|fd| hover_for_builtin(fd, it))
|
||||
.or_else(|| Some(Markup::fenced_block(&it.name()))),
|
||||
@ -370,26 +354,25 @@ fn hover_for_definition(
|
||||
Definition::Local(it) => hover_for_local(it, db),
|
||||
Definition::SelfType(impl_def) => {
|
||||
impl_def.target_ty(db).as_adt().and_then(|adt| match adt {
|
||||
Adt::Struct(it) => from_def_source(db, it, mod_path),
|
||||
Adt::Union(it) => from_def_source(db, it, mod_path),
|
||||
Adt::Enum(it) => from_def_source(db, it, mod_path),
|
||||
Adt::Struct(it) => from_hir_fmt(db, it, mod_path),
|
||||
Adt::Union(it) => from_hir_fmt(db, it, mod_path),
|
||||
Adt::Enum(it) => from_hir_fmt(db, it, mod_path),
|
||||
})
|
||||
}
|
||||
Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
|
||||
Definition::GenericParam(it) => match it {
|
||||
GenericParam::TypeParam(it) => Some(Markup::fenced_block(&it.display(db))),
|
||||
GenericParam::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
|
||||
GenericParam::ConstParam(it) => from_def_source(db, it, None),
|
||||
GenericParam::ConstParam(it) => Some(Markup::fenced_block(&it.display(db))),
|
||||
},
|
||||
};
|
||||
|
||||
fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
|
||||
fn from_hir_fmt<D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
|
||||
where
|
||||
D: HasSource<Ast = A> + HasAttrs + Copy,
|
||||
A: ShortLabel,
|
||||
D: HasAttrs + HirDisplay,
|
||||
{
|
||||
let short_label = def.source(db)?.value.short_label();
|
||||
from_def_source_labeled(db, def, short_label, mod_path)
|
||||
let label = def.display(db).to_string();
|
||||
from_def_source_labeled(db, def, Some(label), mod_path)
|
||||
}
|
||||
|
||||
fn from_def_source_labeled<D>(
|
||||
@ -670,7 +653,9 @@ fn main() { let foo_test = fo$0o(); }
|
||||
```
|
||||
|
||||
```rust
|
||||
pub fn foo<'a, T: AsRef<str>>(b: &'a T) -> &'a str
|
||||
pub fn foo<'a, T>(b: &'a T) -> &'a str
|
||||
where
|
||||
T: AsRef<str>,
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
@ -878,7 +863,7 @@ fn main() { So$0me(12); }
|
||||
```
|
||||
|
||||
```rust
|
||||
Some
|
||||
Some(T)
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
@ -944,7 +929,7 @@ fn main() {
|
||||
```
|
||||
|
||||
```rust
|
||||
Some
|
||||
Some(T)
|
||||
```
|
||||
|
||||
---
|
||||
@ -1441,13 +1426,14 @@ fn bar() { fo$0o(); }
|
||||
```
|
||||
"#]],
|
||||
);
|
||||
// Top level `pub(crate)` will be displayed as no visibility.
|
||||
check(
|
||||
r#"pub(crate) async unsafe extern "C" fn foo$0() {}"#,
|
||||
r#"mod m { pub(crate) async unsafe extern "C" fn foo$0() {} }"#,
|
||||
expect![[r#"
|
||||
*foo*
|
||||
|
||||
```rust
|
||||
test
|
||||
test::m
|
||||
```
|
||||
|
||||
```rust
|
||||
@ -1489,11 +1475,18 @@ extern crate st$0d;
|
||||
//! abc123
|
||||
"#,
|
||||
expect![[r#"
|
||||
*std*
|
||||
Standard library for this test
|
||||
*std*
|
||||
|
||||
Printed?
|
||||
abc123
|
||||
```rust
|
||||
extern crate std
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Standard library for this test
|
||||
|
||||
Printed?
|
||||
abc123
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
@ -1507,11 +1500,18 @@ extern crate std as ab$0c;
|
||||
//! abc123
|
||||
"#,
|
||||
expect![[r#"
|
||||
*abc*
|
||||
Standard library for this test
|
||||
*abc*
|
||||
|
||||
Printed?
|
||||
abc123
|
||||
```rust
|
||||
extern crate std
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Standard library for this test
|
||||
|
||||
Printed?
|
||||
abc123
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -2021,7 +2021,7 @@ enum E {
|
||||
```
|
||||
|
||||
```rust
|
||||
V
|
||||
V { field: i32 }
|
||||
```
|
||||
|
||||
---
|
||||
@ -2417,7 +2417,7 @@ fn main() { let s$0t = S{ f1:Arg(0) }; }
|
||||
focus_range: 24..25,
|
||||
name: "S",
|
||||
kind: Struct,
|
||||
description: "struct S",
|
||||
description: "struct S<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -2463,7 +2463,7 @@ fn main() { let s$0t = S{ f1: S{ f1: Arg(0) } }; }
|
||||
focus_range: 24..25,
|
||||
name: "S",
|
||||
kind: Struct,
|
||||
description: "struct S",
|
||||
description: "struct S<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -2605,7 +2605,7 @@ fn main() { let s$0t = foo(); }
|
||||
focus_range: 6..9,
|
||||
name: "Foo",
|
||||
kind: Trait,
|
||||
description: "trait Foo",
|
||||
description: "trait Foo<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -2702,7 +2702,7 @@ fn main() { let s$0t = foo(); }
|
||||
focus_range: 6..9,
|
||||
name: "Foo",
|
||||
kind: Trait,
|
||||
description: "trait Foo",
|
||||
description: "trait Foo<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -2715,7 +2715,7 @@ fn main() { let s$0t = foo(); }
|
||||
focus_range: 22..25,
|
||||
name: "Bar",
|
||||
kind: Trait,
|
||||
description: "trait Bar",
|
||||
description: "trait Bar<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -2819,7 +2819,7 @@ fn foo(ar$0g: &impl Foo + Bar<S>) {}
|
||||
focus_range: 19..22,
|
||||
name: "Bar",
|
||||
kind: Trait,
|
||||
description: "trait Bar",
|
||||
description: "trait Bar<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -2916,7 +2916,7 @@ fn foo(ar$0g: &impl Foo<S>) {}
|
||||
focus_range: 6..9,
|
||||
name: "Foo",
|
||||
kind: Trait,
|
||||
description: "trait Foo",
|
||||
description: "trait Foo<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -2966,7 +2966,7 @@ fn main() { let s$0t = foo(); }
|
||||
focus_range: 49..50,
|
||||
name: "B",
|
||||
kind: Struct,
|
||||
description: "struct B",
|
||||
description: "struct B<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -3042,7 +3042,7 @@ fn foo(ar$0g: &dyn Foo<S>) {}
|
||||
focus_range: 6..9,
|
||||
name: "Foo",
|
||||
kind: Trait,
|
||||
description: "trait Foo",
|
||||
description: "trait Foo<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -3090,7 +3090,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
|
||||
focus_range: 6..15,
|
||||
name: "ImplTrait",
|
||||
kind: Trait,
|
||||
description: "trait ImplTrait",
|
||||
description: "trait ImplTrait<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -3103,7 +3103,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
|
||||
focus_range: 50..51,
|
||||
name: "B",
|
||||
kind: Struct,
|
||||
description: "struct B",
|
||||
description: "struct B<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -3116,7 +3116,7 @@ fn foo(a$0rg: &impl ImplTrait<B<dyn DynTrait<B<S>>>>) {}
|
||||
focus_range: 28..36,
|
||||
name: "DynTrait",
|
||||
kind: Trait,
|
||||
description: "trait DynTrait",
|
||||
description: "trait DynTrait<T>",
|
||||
},
|
||||
},
|
||||
HoverGotoTypeData {
|
||||
@ -3582,6 +3582,17 @@ mod foo$0;
|
||||
"#,
|
||||
expect![[r#"
|
||||
*foo*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
mod foo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
For the horde!
|
||||
"#]],
|
||||
);
|
||||
@ -3606,7 +3617,7 @@ use foo::bar::{self$0};
|
||||
```
|
||||
|
||||
```rust
|
||||
pub mod bar
|
||||
mod bar
|
||||
```
|
||||
|
||||
---
|
||||
@ -3657,4 +3668,43 @@ cosnt _: &str$0 = ""; }"#;
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hover_macro_expanded_function() {
|
||||
check(
|
||||
r#"
|
||||
struct S<'a, T>(&'a T);
|
||||
trait Clone {}
|
||||
macro_rules! foo {
|
||||
() => {
|
||||
fn bar<'t, T: Clone + 't>(s: &mut S<'t, T>, t: u32) -> *mut u32 where
|
||||
't: 't + 't,
|
||||
for<'a> T: Clone + 'a
|
||||
{ 0 as _ }
|
||||
};
|
||||
}
|
||||
|
||||
foo!();
|
||||
|
||||
fn main() {
|
||||
bar$0;
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
*bar*
|
||||
|
||||
```rust
|
||||
test
|
||||
```
|
||||
|
||||
```rust
|
||||
fn bar<'t, T>(s: &mut S<'t, T>, t: u32) -> *mut u32
|
||||
where
|
||||
T: Clone + 't,
|
||||
't: 't + 't,
|
||||
for<'a> T: Clone + 'a,
|
||||
```
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ fn foo(s: S) { s.$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd foo u32
|
||||
me bar() -> ()
|
||||
me bar() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -97,7 +97,7 @@ impl S {
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd the_field (u32,)
|
||||
me foo() -> ()
|
||||
me foo() fn(self)
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
@ -113,7 +113,7 @@ impl A {
|
||||
"#,
|
||||
expect![[r#"
|
||||
fd the_field (u32, i32)
|
||||
me foo() -> ()
|
||||
me foo() fn(&self)
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
@ -163,7 +163,7 @@ mod m {
|
||||
fn foo(a: A) { a.$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
me the_method() -> ()
|
||||
me the_method() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -196,7 +196,7 @@ impl A<i32> {
|
||||
fn foo(a: A<u32>) { a.$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
me the_method() -> ()
|
||||
me the_method() fn(&self)
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
@ -211,7 +211,7 @@ impl Trait for A {}
|
||||
fn foo(a: A) { a.$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
me the_method() -> ()
|
||||
me the_method() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -226,7 +226,7 @@ impl<T> Trait for T {}
|
||||
fn foo(a: &A) { a.$0 }
|
||||
",
|
||||
expect![[r#"
|
||||
me the_method() -> ()
|
||||
me the_method() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -244,7 +244,7 @@ impl Trait for A {}
|
||||
fn foo(a: A) { a.$0 }
|
||||
",
|
||||
expect![[r#"
|
||||
me the_method() -> ()
|
||||
me the_method() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -298,7 +298,7 @@ impl T {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me blah() -> ()
|
||||
me blah() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -407,7 +407,7 @@ fn foo() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me the_method() -> ()
|
||||
me the_method() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -422,7 +422,7 @@ macro_rules! make_s { () => { S }; }
|
||||
fn main() { make_s!().f$0; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
me foo() -> ()
|
||||
me foo() fn(&self)
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
@ -450,7 +450,7 @@ mod foo {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me private() -> ()
|
||||
me private() fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -402,7 +402,7 @@ fn main() {
|
||||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
fn weird_function() (dep::test_mod::TestTrait) -> ()
|
||||
fn weird_function() (dep::test_mod::TestTrait) fn()
|
||||
"#]],
|
||||
);
|
||||
|
||||
@ -495,7 +495,7 @@ fn main() {
|
||||
check(
|
||||
fixture,
|
||||
expect![[r#"
|
||||
me random_method() (dep::test_mod::TestTrait) -> ()
|
||||
me random_method() (dep::test_mod::TestTrait) fn(&self)
|
||||
"#]],
|
||||
);
|
||||
|
||||
@ -665,7 +665,7 @@ fn main() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
me random_method() (dep::test_mod::TestTrait) -> () DEPRECATED
|
||||
me random_method() (dep::test_mod::TestTrait) fn(&self) DEPRECATED
|
||||
"#]],
|
||||
);
|
||||
|
||||
@ -696,7 +696,7 @@ fn main() {
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct SPECIAL_CONST (dep::test_mod::TestTrait) DEPRECATED
|
||||
fn weird_function() (dep::test_mod::TestTrait) -> () DEPRECATED
|
||||
fn weird_function() (dep::test_mod::TestTrait) fn() DEPRECATED
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -359,8 +359,8 @@ impl S {
|
||||
fn foo() { let _ = S::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn a() -> ()
|
||||
me b(…) -> ()
|
||||
fn a() fn()
|
||||
me b(…) fn(&self)
|
||||
ct C const C: i32 = 42;
|
||||
ta T type T = i32;
|
||||
"#]],
|
||||
@ -387,7 +387,7 @@ mod m {
|
||||
fn foo() { let _ = S::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn public_method() -> ()
|
||||
fn public_method() fn()
|
||||
ct PUBLIC_CONST pub(crate) const PUBLIC_CONST: u32 = 1;
|
||||
ta PublicType pub(crate) type PublicType = u32;
|
||||
"#]],
|
||||
@ -404,7 +404,7 @@ impl E { fn m() { } }
|
||||
fn foo() { let _ = E::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn m() -> ()
|
||||
fn m() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -419,7 +419,7 @@ impl U { fn m() { } }
|
||||
fn foo() { let _ = U::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn m() -> ()
|
||||
fn m() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -449,7 +449,7 @@ trait Trait { fn m(); }
|
||||
fn foo() { let _ = Trait::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn m() -> ()
|
||||
fn m() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -466,7 +466,7 @@ impl Trait for S {}
|
||||
fn foo() { let _ = S::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn m() -> ()
|
||||
fn m() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -483,7 +483,7 @@ impl Trait for S {}
|
||||
fn foo() { let _ = <S as Trait>::$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn m() -> ()
|
||||
fn m() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -512,11 +512,11 @@ fn foo<T: Sub>() { T::$0 }
|
||||
ta SubTy type SubTy;
|
||||
ta Ty type Ty;
|
||||
ct C2 const C2: ();
|
||||
fn subfunc() -> ()
|
||||
me submethod(…) -> ()
|
||||
fn subfunc() fn()
|
||||
me submethod(…) fn(&self)
|
||||
ct CONST const CONST: u8;
|
||||
fn func() -> ()
|
||||
me method(…) -> ()
|
||||
fn func() fn()
|
||||
me method(…) fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -552,11 +552,11 @@ impl<T> Sub for Wrap<T> {
|
||||
ta SubTy type SubTy;
|
||||
ta Ty type Ty;
|
||||
ct CONST const CONST: u8 = 0;
|
||||
fn func() -> ()
|
||||
me method(…) -> ()
|
||||
fn func() fn()
|
||||
me method(…) fn(&self)
|
||||
ct C2 const C2: () = ();
|
||||
fn subfunc() -> ()
|
||||
me submethod(…) -> ()
|
||||
fn subfunc() fn()
|
||||
me submethod(…) fn(&self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -573,8 +573,8 @@ impl T { fn bar() {} }
|
||||
fn main() { T::$0; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() -> ()
|
||||
fn bar() -> ()
|
||||
fn foo() fn()
|
||||
fn bar() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -589,7 +589,7 @@ macro_rules! foo { () => {} }
|
||||
fn main() { let _ = crate::$0 }
|
||||
"#,
|
||||
expect![[r##"
|
||||
fn main() -> ()
|
||||
fn main() fn()
|
||||
ma foo!(…) #[macro_export] macro_rules! foo
|
||||
"##]],
|
||||
);
|
||||
@ -633,7 +633,7 @@ mod p {
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct RIGHT_CONST
|
||||
fn right_fn() -> ()
|
||||
fn right_fn() fn()
|
||||
st RightType
|
||||
"#]],
|
||||
);
|
||||
@ -680,8 +680,8 @@ fn main() { m!(self::f$0); }
|
||||
fn foo() {}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() -> ()
|
||||
fn foo() -> ()
|
||||
fn main() fn()
|
||||
fn foo() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -699,7 +699,7 @@ mod m {
|
||||
"#,
|
||||
expect![[r#"
|
||||
md z
|
||||
fn z() -> ()
|
||||
fn z() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -719,7 +719,7 @@ fn foo() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn new() -> HashMap<K, V, RandomState>
|
||||
fn new() fn() -> HashMap<K, V, RandomState>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -752,8 +752,8 @@ fn main() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() -> ()
|
||||
fn foo(…) -> ()
|
||||
fn main() fn()
|
||||
fn foo(…) fn(i32, i32)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -776,7 +776,7 @@ impl Foo {
|
||||
expect![[r#"
|
||||
ev Bar ()
|
||||
ev Baz ()
|
||||
me foo(…) -> ()
|
||||
me foo(…) fn(self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -800,7 +800,7 @@ impl u8 {
|
||||
"#,
|
||||
expect![[r#"
|
||||
ct MAX pub const MAX: Self = 255;
|
||||
me func(…) -> ()
|
||||
me func(…) fn(self)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ fn quux(x: i32) {
|
||||
expect![[r#"
|
||||
lc y i32
|
||||
lc x i32
|
||||
fn quux(…) -> ()
|
||||
fn quux(…) fn(i32)
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -157,7 +157,7 @@ fn quux() {
|
||||
expect![[r#"
|
||||
lc b i32
|
||||
lc a
|
||||
fn quux() -> ()
|
||||
fn quux() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -172,7 +172,7 @@ fn quux() {
|
||||
"#,
|
||||
expect![[r#"
|
||||
lc x
|
||||
fn quux() -> ()
|
||||
fn quux() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -203,14 +203,14 @@ fn main() {
|
||||
r#"fn quux<T>() { $0 }"#,
|
||||
expect![[r#"
|
||||
tp T
|
||||
fn quux() -> ()
|
||||
fn quux() fn()
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"fn quux<const C: usize>() { $0 }"#,
|
||||
expect![[r#"
|
||||
cp C
|
||||
fn quux() -> ()
|
||||
fn quux() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -221,7 +221,7 @@ fn main() {
|
||||
check(
|
||||
r#"fn quux<'a>() { $0 }"#,
|
||||
expect![[r#"
|
||||
fn quux() -> ()
|
||||
fn quux() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -259,7 +259,7 @@ fn quux() { $0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
st S
|
||||
fn quux() -> ()
|
||||
fn quux() fn()
|
||||
en E
|
||||
"#]],
|
||||
);
|
||||
@ -312,7 +312,7 @@ mod m {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn quux() -> ()
|
||||
fn quux() fn()
|
||||
st Bar
|
||||
"#]],
|
||||
);
|
||||
@ -327,7 +327,7 @@ fn x() -> $0
|
||||
"#,
|
||||
expect![[r#"
|
||||
st Foo
|
||||
fn x() -> ()
|
||||
fn x() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -348,7 +348,7 @@ fn foo() {
|
||||
expect![[r#"
|
||||
lc bar i32
|
||||
lc bar i32
|
||||
fn foo() -> ()
|
||||
fn foo() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -378,7 +378,7 @@ use prelude::*;
|
||||
mod prelude { struct Option; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() -> ()
|
||||
fn foo() fn()
|
||||
md std
|
||||
st Option
|
||||
"#]],
|
||||
@ -408,7 +408,7 @@ mod macros {
|
||||
}
|
||||
"#,
|
||||
expect![[r##"
|
||||
fn f() -> ()
|
||||
fn f() fn()
|
||||
ma concat!(…) #[macro_export] macro_rules! concat
|
||||
md std
|
||||
"##]],
|
||||
@ -435,7 +435,7 @@ use prelude::*;
|
||||
mod prelude { struct String; }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() -> ()
|
||||
fn foo() fn()
|
||||
md std
|
||||
md core
|
||||
st String
|
||||
@ -466,7 +466,7 @@ fn main() { let v = $0 }
|
||||
expect![[r##"
|
||||
md m1
|
||||
ma baz!(…) #[macro_export] macro_rules! baz
|
||||
fn main() -> ()
|
||||
fn main() fn()
|
||||
md m2
|
||||
ma bar!(…) macro_rules! bar
|
||||
ma foo!(…) macro_rules! foo
|
||||
@ -482,7 +482,7 @@ macro_rules! foo { () => {} }
|
||||
fn foo() { $0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn foo() -> ()
|
||||
fn foo() fn()
|
||||
ma foo!(…) macro_rules! foo
|
||||
"#]],
|
||||
);
|
||||
@ -496,7 +496,7 @@ macro_rules! foo { () => {} }
|
||||
fn main() { let x: $0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() -> ()
|
||||
fn main() fn()
|
||||
ma foo!(…) macro_rules! foo
|
||||
"#]],
|
||||
);
|
||||
@ -510,7 +510,7 @@ macro_rules! foo { () => {} }
|
||||
fn main() { $0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() -> ()
|
||||
fn main() fn()
|
||||
ma foo!(…) macro_rules! foo
|
||||
"#]],
|
||||
);
|
||||
@ -526,8 +526,8 @@ fn main() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn frobnicate() -> ()
|
||||
fn main() -> ()
|
||||
fn frobnicate() fn()
|
||||
fn main() fn()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
@ -545,7 +545,7 @@ fn quux(x: i32) {
|
||||
expect![[r#"
|
||||
lc y i32
|
||||
lc x i32
|
||||
fn quux(…) -> ()
|
||||
fn quux(…) fn(i32)
|
||||
ma m!(…) macro_rules! m
|
||||
"#]],
|
||||
);
|
||||
@ -564,7 +564,7 @@ fn quux(x: i32) {
|
||||
expect![[r#"
|
||||
lc y i32
|
||||
lc x i32
|
||||
fn quux(…) -> ()
|
||||
fn quux(…) fn(i32)
|
||||
ma m!(…) macro_rules! m
|
||||
"#]],
|
||||
);
|
||||
@ -583,7 +583,7 @@ fn quux(x: i32) {
|
||||
expect![[r#"
|
||||
lc y i32
|
||||
lc x i32
|
||||
fn quux(…) -> ()
|
||||
fn quux(…) fn(i32)
|
||||
ma m!(…) macro_rules! m
|
||||
"#]],
|
||||
);
|
||||
@ -598,7 +598,7 @@ use spam::Quux;
|
||||
fn main() { $0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
fn main() -> ()
|
||||
fn main() fn()
|
||||
?? Quux
|
||||
"#]],
|
||||
);
|
||||
@ -616,7 +616,7 @@ fn main() { let foo: Foo = Q$0 }
|
||||
ev Foo::Baz ()
|
||||
ev Foo::Quux ()
|
||||
en Foo
|
||||
fn main() -> ()
|
||||
fn main() fn()
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
@ -631,7 +631,7 @@ fn f() -> m::E { V$0 }
|
||||
expect![[r#"
|
||||
ev m::E::V ()
|
||||
md m
|
||||
fn f() -> E
|
||||
fn f() fn() -> E
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ fn foo() {
|
||||
bar.fo$0;
|
||||
}
|
||||
"#,
|
||||
DetailAndDocumentation { detail: "-> ()", documentation: "Do the foo" },
|
||||
DetailAndDocumentation { detail: "fn(&self)", documentation: "Do the foo" },
|
||||
);
|
||||
}
|
||||
|
||||
@ -255,7 +255,7 @@ fn foo() {
|
||||
bar.fo$0;
|
||||
}
|
||||
"#,
|
||||
DetailAndDocumentation { detail: "-> ()", documentation: " Do the foo" },
|
||||
DetailAndDocumentation { detail: "fn(&self)", documentation: " Do the foo" },
|
||||
);
|
||||
}
|
||||
|
||||
@ -273,7 +273,7 @@ fn bar() {
|
||||
for c in fo$0
|
||||
}
|
||||
"#,
|
||||
DetailAndDocumentation { detail: "-> &str", documentation: "Do the foo" },
|
||||
DetailAndDocumentation { detail: "fn() -> &str", documentation: "Do the foo" },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -451,6 +451,44 @@ fn main() { Foo::Fo$0 }
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_detail_includes_args_and_return_type() {
|
||||
check(
|
||||
r#"
|
||||
fn foo<T>(a: u32, b: u32, t: T) -> (u32, T) { (a, t) }
|
||||
|
||||
fn main() { fo$0 }
|
||||
"#,
|
||||
expect![[r#"
|
||||
[
|
||||
CompletionItem {
|
||||
label: "foo(…)",
|
||||
source_range: 68..70,
|
||||
delete: 68..70,
|
||||
insert: "foo(${1:a}, ${2:b}, ${3:t})$0",
|
||||
kind: SymbolKind(
|
||||
Function,
|
||||
),
|
||||
lookup: "foo",
|
||||
detail: "fn(u32, u32, T) -> (u32, T)",
|
||||
trigger_call_info: true,
|
||||
},
|
||||
CompletionItem {
|
||||
label: "main()",
|
||||
source_range: 68..70,
|
||||
delete: 68..70,
|
||||
insert: "main()$0",
|
||||
kind: SymbolKind(
|
||||
Function,
|
||||
),
|
||||
lookup: "main",
|
||||
detail: "fn()",
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_detail_just_parentheses_for_unit() {
|
||||
check(
|
||||
@ -538,7 +576,7 @@ fn main() { let _: m::Spam = S$0 }
|
||||
Function,
|
||||
),
|
||||
lookup: "main",
|
||||
detail: "-> ()",
|
||||
detail: "fn()",
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
@ -567,7 +605,7 @@ fn main() { som$0 }
|
||||
Function,
|
||||
),
|
||||
lookup: "main",
|
||||
detail: "-> ()",
|
||||
detail: "fn()",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "something_deprecated()",
|
||||
@ -578,7 +616,7 @@ fn main() { som$0 }
|
||||
Function,
|
||||
),
|
||||
lookup: "something_deprecated",
|
||||
detail: "-> ()",
|
||||
detail: "fn()",
|
||||
deprecated: true,
|
||||
},
|
||||
CompletionItem {
|
||||
@ -590,7 +628,7 @@ fn main() { som$0 }
|
||||
Function,
|
||||
),
|
||||
lookup: "something_else_deprecated",
|
||||
detail: "-> ()",
|
||||
detail: "fn()",
|
||||
deprecated: true,
|
||||
},
|
||||
]
|
||||
@ -641,7 +679,7 @@ impl S {
|
||||
insert: "bar()$0",
|
||||
kind: Method,
|
||||
lookup: "bar",
|
||||
detail: "-> ()",
|
||||
detail: "fn(self)",
|
||||
documentation: Documentation(
|
||||
"Method docs",
|
||||
),
|
||||
@ -741,7 +779,7 @@ fn foo(s: S) { s.$0 }
|
||||
insert: "the_method()$0",
|
||||
kind: Method,
|
||||
lookup: "the_method",
|
||||
detail: "-> ()",
|
||||
detail: "fn(&self)",
|
||||
},
|
||||
]
|
||||
"#]],
|
||||
@ -1049,7 +1087,7 @@ fn main() {
|
||||
Function,
|
||||
),
|
||||
lookup: "foo",
|
||||
detail: "-> ()",
|
||||
detail: "fn(&mut S)",
|
||||
trigger_call_info: true,
|
||||
},
|
||||
CompletionItem {
|
||||
@ -1061,7 +1099,7 @@ fn main() {
|
||||
Function,
|
||||
),
|
||||
lookup: "main",
|
||||
detail: "-> ()",
|
||||
detail: "fn()",
|
||||
},
|
||||
CompletionItem {
|
||||
label: "s",
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
use hir::{HasSource, HirDisplay, Type};
|
||||
use ide_db::SymbolKind;
|
||||
use itertools::Itertools;
|
||||
use syntax::ast::Fn;
|
||||
|
||||
use crate::{
|
||||
@ -73,8 +74,42 @@ impl<'a> FunctionRender<'a> {
|
||||
}
|
||||
|
||||
fn detail(&self) -> String {
|
||||
let ty = self.func.ret_type(self.ctx.db());
|
||||
format!("-> {}", ty.display(self.ctx.db()))
|
||||
let ret_ty = self.func.ret_type(self.ctx.db());
|
||||
let ret = if ret_ty.is_unit() {
|
||||
// Omit the return type if it is the unit type
|
||||
String::new()
|
||||
} else {
|
||||
format!(" {}", self.ty_display())
|
||||
};
|
||||
|
||||
format!("fn({}){}", self.params_display(), ret)
|
||||
}
|
||||
|
||||
fn params_display(&self) -> String {
|
||||
if let Some(self_param) = self.func.self_param(self.ctx.db()) {
|
||||
let params = self
|
||||
.func
|
||||
.assoc_fn_params(self.ctx.db())
|
||||
.into_iter()
|
||||
.skip(1) // skip the self param because we are manually handling that
|
||||
.map(|p| p.ty().display(self.ctx.db()).to_string());
|
||||
|
||||
std::iter::once(self_param.display(self.ctx.db()).to_owned()).chain(params).join(", ")
|
||||
} else {
|
||||
let params = self
|
||||
.func
|
||||
.assoc_fn_params(self.ctx.db())
|
||||
.into_iter()
|
||||
.map(|p| p.ty().display(self.ctx.db()).to_string())
|
||||
.join(", ");
|
||||
params
|
||||
}
|
||||
}
|
||||
|
||||
fn ty_display(&self) -> String {
|
||||
let ret_ty = self.func.ret_type(self.ctx.db());
|
||||
|
||||
format!("-> {}", ret_ty.display(self.ctx.db()))
|
||||
}
|
||||
|
||||
fn add_arg(&self, arg: &str, ty: &Type) -> String {
|
||||
|
Loading…
Reference in New Issue
Block a user