2022-12-01 09:39:57 -06:00
|
|
|
use std::{
|
|
|
|
fmt::{self, Write},
|
|
|
|
mem::take,
|
|
|
|
};
|
2022-08-31 11:34:10 -05:00
|
|
|
|
2020-10-20 10:04:38 -05:00
|
|
|
use either::Either;
|
2022-12-01 09:39:57 -06:00
|
|
|
use hir::{known, HasVisibility, HirDisplay, HirWrite, ModuleDef, ModuleDefId, Semantics};
|
2022-12-16 10:13:46 -06:00
|
|
|
use ide_db::{base_db::FileRange, famous_defs::FamousDefs, RootDatabase};
|
2021-10-03 08:31:35 -05:00
|
|
|
use itertools::Itertools;
|
2022-12-01 09:39:57 -06:00
|
|
|
use stdx::never;
|
2020-08-12 11:26:51 -05:00
|
|
|
use syntax::{
|
2022-12-16 10:13:46 -06:00
|
|
|
ast::{self, AstNode},
|
|
|
|
match_ast, NodeOrToken, SyntaxNode, TextRange, TextSize,
|
2019-07-19 16:20:09 -05:00
|
|
|
};
|
2019-12-21 11:45:46 -06:00
|
|
|
|
2022-12-01 09:39:57 -06:00
|
|
|
use crate::{navigation_target::TryToNav, FileId};
|
2020-07-16 11:07:53 -05:00
|
|
|
|
2022-12-16 10:13:46 -06:00
|
|
|
mod closing_brace;
|
|
|
|
mod implicit_static;
|
|
|
|
mod fn_lifetime_fn;
|
|
|
|
mod closure_ret;
|
|
|
|
mod adjustment;
|
|
|
|
mod chaining;
|
|
|
|
mod param_name;
|
|
|
|
mod binding_mode;
|
|
|
|
mod bind_pat;
|
|
|
|
|
2020-03-10 13:21:56 -05:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2020-03-31 09:02:55 -05:00
|
|
|
pub struct InlayHintsConfig {
|
2022-12-21 09:24:49 -06:00
|
|
|
pub location_links: bool,
|
2022-03-11 14:06:26 -06:00
|
|
|
pub render_colons: bool,
|
2020-03-11 22:14:39 -05:00
|
|
|
pub type_hints: bool,
|
|
|
|
pub parameter_hints: bool,
|
2020-03-23 14:32:05 -05:00
|
|
|
pub chaining_hints: bool,
|
2022-11-04 11:11:15 -05:00
|
|
|
pub adjustment_hints: AdjustmentHints,
|
2022-12-21 12:18:12 -06:00
|
|
|
pub adjustment_hints_hide_outside_unsafe: bool,
|
2022-05-28 07:13:25 -05:00
|
|
|
pub closure_return_type_hints: ClosureReturnTypeHints,
|
2022-05-14 07:26:08 -05:00
|
|
|
pub binding_mode_hints: bool,
|
2022-03-19 13:01:19 -05:00
|
|
|
pub lifetime_elision_hints: LifetimeElisionHints,
|
2022-03-19 12:11:56 -05:00
|
|
|
pub param_names_for_lifetime_elision_hints: bool,
|
2021-11-13 17:12:29 -06:00
|
|
|
pub hide_named_constructor_hints: bool,
|
2022-05-15 06:17:52 -05:00
|
|
|
pub hide_closure_initialization_hints: bool,
|
2020-03-10 13:21:56 -05:00
|
|
|
pub max_length: Option<usize>,
|
2022-05-13 12:42:59 -05:00
|
|
|
pub closing_brace_hints_min_lines: Option<usize>,
|
2020-03-10 13:21:56 -05:00
|
|
|
}
|
|
|
|
|
2022-05-28 07:13:25 -05:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
pub enum ClosureReturnTypeHints {
|
|
|
|
Always,
|
|
|
|
WithBlock,
|
|
|
|
Never,
|
|
|
|
}
|
|
|
|
|
2022-03-19 13:01:19 -05:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
|
|
pub enum LifetimeElisionHints {
|
|
|
|
Always,
|
|
|
|
SkipTrivial,
|
|
|
|
Never,
|
|
|
|
}
|
|
|
|
|
2022-05-12 06:39:32 -05:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2022-11-04 11:11:15 -05:00
|
|
|
pub enum AdjustmentHints {
|
2022-05-12 06:39:32 -05:00
|
|
|
Always,
|
2022-11-04 16:59:07 -05:00
|
|
|
ReborrowOnly,
|
2022-05-12 06:39:32 -05:00
|
|
|
Never,
|
|
|
|
}
|
|
|
|
|
2020-03-10 13:21:56 -05:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2019-07-19 16:20:09 -05:00
|
|
|
pub enum InlayKind {
|
2022-05-14 07:26:08 -05:00
|
|
|
BindingModeHint,
|
2020-03-23 14:32:05 -05:00
|
|
|
ChainingHint,
|
2022-05-17 07:46:43 -05:00
|
|
|
ClosingBraceHint,
|
2022-04-26 04:46:03 -05:00
|
|
|
ClosureReturnTypeHint,
|
2022-03-18 12:11:16 -05:00
|
|
|
GenericParamListHint,
|
2022-11-04 11:11:15 -05:00
|
|
|
AdjustmentHint,
|
2022-03-18 12:11:16 -05:00
|
|
|
LifetimeHint,
|
2022-04-26 04:46:03 -05:00
|
|
|
ParameterHint,
|
|
|
|
TypeHint,
|
2022-12-16 13:52:31 -06:00
|
|
|
OpeningParenthesis,
|
|
|
|
ClosingParenthesis,
|
2019-07-19 16:20:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct InlayHint {
|
|
|
|
pub range: TextRange,
|
2019-07-22 13:52:47 -05:00
|
|
|
pub kind: InlayKind,
|
2022-08-31 11:34:10 -05:00
|
|
|
pub label: InlayHintLabel,
|
2022-05-19 06:38:37 -05:00
|
|
|
pub tooltip: Option<InlayTooltip>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum InlayTooltip {
|
|
|
|
String(String),
|
|
|
|
HoverRanged(FileId, TextRange),
|
|
|
|
HoverOffset(FileId, TextSize),
|
2019-07-19 16:20:09 -05:00
|
|
|
}
|
|
|
|
|
2022-12-01 09:39:57 -06:00
|
|
|
#[derive(Default)]
|
2022-08-31 11:34:10 -05:00
|
|
|
pub struct InlayHintLabel {
|
|
|
|
pub parts: Vec<InlayHintLabelPart>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InlayHintLabel {
|
|
|
|
pub fn as_simple_str(&self) -> Option<&str> {
|
|
|
|
match &*self.parts {
|
|
|
|
[part] => part.as_simple_str(),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn prepend_str(&mut self, s: &str) {
|
|
|
|
match &mut *self.parts {
|
|
|
|
[part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text),
|
|
|
|
_ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn append_str(&mut self, s: &str) {
|
|
|
|
match &mut *self.parts {
|
|
|
|
[.., part] if part.as_simple_str().is_some() => part.text.push_str(s),
|
|
|
|
_ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<String> for InlayHintLabel {
|
|
|
|
fn from(s: String) -> Self {
|
|
|
|
Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-04 11:11:15 -05:00
|
|
|
impl From<&str> for InlayHintLabel {
|
|
|
|
fn from(s: &str) -> Self {
|
|
|
|
Self { parts: vec![InlayHintLabelPart { text: s.into(), linked_location: None }] }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-31 11:34:10 -05:00
|
|
|
impl fmt::Display for InlayHintLabel {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(f, "{}", self.parts.iter().map(|part| &part.text).format(""))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for InlayHintLabel {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
f.debug_list().entries(&self.parts).finish()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct InlayHintLabelPart {
|
|
|
|
pub text: String,
|
2022-08-31 11:54:19 -05:00
|
|
|
/// Source location represented by this label part. The client will use this to fetch the part's
|
|
|
|
/// hover tooltip, and Ctrl+Clicking the label part will navigate to the definition the location
|
|
|
|
/// refers to (not necessarily the location itself).
|
|
|
|
/// When setting this, no tooltip must be set on the containing hint, or VS Code will display
|
|
|
|
/// them both.
|
2022-08-31 11:34:10 -05:00
|
|
|
pub linked_location: Option<FileRange>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InlayHintLabelPart {
|
|
|
|
pub fn as_simple_str(&self) -> Option<&str> {
|
|
|
|
match self {
|
|
|
|
Self { text, linked_location: None } => Some(text),
|
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Debug for InlayHintLabelPart {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self.as_simple_str() {
|
|
|
|
Some(string) => string.fmt(f),
|
|
|
|
None => f
|
|
|
|
.debug_struct("InlayHintLabelPart")
|
|
|
|
.field("text", &self.text)
|
|
|
|
.field("linked_location", &self.linked_location)
|
|
|
|
.finish(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-01 09:39:57 -06:00
|
|
|
#[derive(Debug)]
|
|
|
|
struct InlayHintLabelBuilder<'a> {
|
|
|
|
db: &'a RootDatabase,
|
|
|
|
result: InlayHintLabel,
|
|
|
|
last_part: String,
|
2022-12-21 09:24:49 -06:00
|
|
|
location_link_enabled: bool,
|
2022-12-01 09:39:57 -06:00
|
|
|
location: Option<FileRange>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Write for InlayHintLabelBuilder<'_> {
|
|
|
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
|
|
|
self.last_part.write_str(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl HirWrite for InlayHintLabelBuilder<'_> {
|
|
|
|
fn start_location_link(&mut self, def: ModuleDefId) {
|
2022-12-21 09:24:49 -06:00
|
|
|
if !self.location_link_enabled {
|
|
|
|
return;
|
|
|
|
}
|
2022-12-01 09:39:57 -06:00
|
|
|
if self.location.is_some() {
|
|
|
|
never!("location link is already started");
|
|
|
|
}
|
|
|
|
self.make_new_part();
|
|
|
|
let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
|
|
|
|
let location =
|
|
|
|
FileRange { file_id: location.file_id, range: location.focus_or_full_range() };
|
|
|
|
self.location = Some(location);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn end_location_link(&mut self) {
|
2022-12-21 09:24:49 -06:00
|
|
|
if !self.location_link_enabled {
|
|
|
|
return;
|
|
|
|
}
|
2022-12-01 09:39:57 -06:00
|
|
|
self.make_new_part();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl InlayHintLabelBuilder<'_> {
|
|
|
|
fn make_new_part(&mut self) {
|
|
|
|
self.result.parts.push(InlayHintLabelPart {
|
|
|
|
text: take(&mut self.last_part),
|
|
|
|
linked_location: self.location.take(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn finish(mut self) -> InlayHintLabel {
|
|
|
|
self.make_new_part();
|
|
|
|
self.result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn label_of_ty(
|
2022-12-22 05:00:25 -06:00
|
|
|
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
2022-12-01 09:39:57 -06:00
|
|
|
config: &InlayHintsConfig,
|
|
|
|
ty: hir::Type,
|
|
|
|
) -> Option<InlayHintLabel> {
|
|
|
|
fn rec(
|
|
|
|
sema: &Semantics<'_, RootDatabase>,
|
|
|
|
famous_defs: &FamousDefs<'_, '_>,
|
|
|
|
mut max_length: Option<usize>,
|
|
|
|
ty: hir::Type,
|
|
|
|
label_builder: &mut InlayHintLabelBuilder<'_>,
|
|
|
|
) {
|
|
|
|
let iter_item_type = hint_iterator(sema, &famous_defs, &ty);
|
|
|
|
match iter_item_type {
|
|
|
|
Some(ty) => {
|
|
|
|
const LABEL_START: &str = "impl Iterator<Item = ";
|
|
|
|
const LABEL_END: &str = ">";
|
|
|
|
|
|
|
|
max_length =
|
|
|
|
max_length.map(|len| len.saturating_sub(LABEL_START.len() + LABEL_END.len()));
|
|
|
|
|
|
|
|
label_builder.write_str(LABEL_START).unwrap();
|
|
|
|
rec(sema, famous_defs, max_length, ty, label_builder);
|
|
|
|
label_builder.write_str(LABEL_END).unwrap();
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let _ = ty.display_truncated(sema.db, max_length).write_to(label_builder);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut label_builder = InlayHintLabelBuilder {
|
|
|
|
db: sema.db,
|
|
|
|
last_part: String::new(),
|
|
|
|
location: None,
|
2022-12-21 09:24:49 -06:00
|
|
|
location_link_enabled: config.location_links,
|
2022-12-01 09:39:57 -06:00
|
|
|
result: InlayHintLabel::default(),
|
|
|
|
};
|
|
|
|
rec(sema, &famous_defs, config.max_length, ty, &mut label_builder);
|
|
|
|
let r = label_builder.finish();
|
|
|
|
Some(r)
|
|
|
|
}
|
|
|
|
|
2020-05-31 04:29:19 -05:00
|
|
|
// Feature: Inlay Hints
|
|
|
|
//
|
|
|
|
// rust-analyzer shows additional information inline with the source code.
|
|
|
|
// Editors usually render this using read-only virtual text snippets interspersed with code.
|
|
|
|
//
|
2022-03-18 12:11:16 -05:00
|
|
|
// rust-analyzer by default shows hints for
|
2020-05-31 04:29:19 -05:00
|
|
|
//
|
|
|
|
// * types of local variables
|
|
|
|
// * names of function arguments
|
|
|
|
// * types of chained expressions
|
|
|
|
//
|
2022-03-18 12:11:16 -05:00
|
|
|
// Optionally, one can enable additional hints for
|
|
|
|
//
|
2022-05-28 07:13:25 -05:00
|
|
|
// * return types of closure expressions
|
2022-03-19 13:01:19 -05:00
|
|
|
// * elided lifetimes
|
2022-03-20 08:41:27 -05:00
|
|
|
// * compiler inserted reborrows
|
2020-05-31 04:29:19 -05:00
|
|
|
//
|
2021-03-30 18:08:10 -05:00
|
|
|
// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
|
2019-11-18 11:02:28 -06:00
|
|
|
pub(crate) fn inlay_hints(
|
|
|
|
db: &RootDatabase,
|
|
|
|
file_id: FileId,
|
2022-11-07 10:21:37 -06:00
|
|
|
range_limit: Option<TextRange>,
|
2020-03-31 09:02:55 -05:00
|
|
|
config: &InlayHintsConfig,
|
2019-11-18 11:02:28 -06:00
|
|
|
) -> Vec<InlayHint> {
|
2020-08-12 09:32:36 -05:00
|
|
|
let _p = profile::span("inlay_hints");
|
2020-02-18 11:35:10 -06:00
|
|
|
let sema = Semantics::new(db);
|
|
|
|
let file = sema.parse(file_id);
|
2021-09-14 13:30:28 -05:00
|
|
|
let file = file.syntax();
|
2020-02-29 16:24:50 -06:00
|
|
|
|
2022-03-16 15:16:55 -05:00
|
|
|
let mut acc = Vec::new();
|
2022-02-11 16:48:01 -06:00
|
|
|
|
2022-05-30 06:51:48 -05:00
|
|
|
if let Some(scope) = sema.scope(&file) {
|
|
|
|
let famous_defs = FamousDefs(&sema, scope.krate());
|
|
|
|
|
|
|
|
let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
|
|
|
|
match range_limit {
|
2022-11-07 10:21:37 -06:00
|
|
|
Some(range) => match file.covering_element(range) {
|
2022-05-30 06:51:48 -05:00
|
|
|
NodeOrToken::Token(_) => return acc,
|
|
|
|
NodeOrToken::Node(n) => n
|
|
|
|
.descendants()
|
|
|
|
.filter(|descendant| range.intersect(descendant.text_range()).is_some())
|
|
|
|
.for_each(hints),
|
|
|
|
},
|
|
|
|
None => file.descendants().for_each(hints),
|
|
|
|
};
|
|
|
|
}
|
2022-02-11 16:48:01 -06:00
|
|
|
|
2022-03-16 15:16:55 -05:00
|
|
|
acc
|
2022-02-11 16:48:01 -06:00
|
|
|
}
|
|
|
|
|
2022-03-16 15:16:55 -05:00
|
|
|
fn hints(
|
2022-02-11 16:48:01 -06:00
|
|
|
hints: &mut Vec<InlayHint>,
|
2022-12-22 05:00:25 -06:00
|
|
|
famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
|
2022-02-11 16:48:01 -06:00
|
|
|
config: &InlayHintsConfig,
|
2022-05-19 06:38:37 -05:00
|
|
|
file_id: FileId,
|
2022-02-11 16:48:01 -06:00
|
|
|
node: SyntaxNode,
|
|
|
|
) {
|
2022-12-16 10:13:46 -06:00
|
|
|
closing_brace::hints(hints, sema, config, file_id, node.clone());
|
2022-05-17 05:18:07 -05:00
|
|
|
match_ast! {
|
|
|
|
match node {
|
|
|
|
ast::Expr(expr) => {
|
2022-12-22 05:00:25 -06:00
|
|
|
chaining::hints(hints, famous_defs, config, file_id, &expr);
|
2022-12-16 10:13:46 -06:00
|
|
|
adjustment::hints(hints, sema, config, &expr);
|
2022-05-17 05:18:07 -05:00
|
|
|
match expr {
|
2022-12-16 10:13:46 -06:00
|
|
|
ast::Expr::CallExpr(it) => param_name::hints(hints, sema, config, ast::Expr::from(it)),
|
2022-05-17 05:18:07 -05:00
|
|
|
ast::Expr::MethodCallExpr(it) => {
|
2022-12-16 10:13:46 -06:00
|
|
|
param_name::hints(hints, sema, config, ast::Expr::from(it))
|
2022-05-17 05:18:07 -05:00
|
|
|
}
|
2022-12-22 05:00:25 -06:00
|
|
|
ast::Expr::ClosureExpr(it) => closure_ret::hints(hints, famous_defs, config, file_id, it),
|
2022-05-17 05:18:07 -05:00
|
|
|
// We could show reborrows for all expressions, but usually that is just noise to the user
|
|
|
|
// and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
|
2022-11-04 11:11:15 -05:00
|
|
|
// ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
|
2022-05-17 05:18:07 -05:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
},
|
|
|
|
ast::Pat(it) => {
|
2022-12-16 10:13:46 -06:00
|
|
|
binding_mode::hints(hints, sema, config, &it);
|
2022-05-17 05:18:07 -05:00
|
|
|
if let ast::Pat::IdentPat(it) = it {
|
2022-12-22 05:00:25 -06:00
|
|
|
bind_pat::hints(hints, famous_defs, config, file_id, &it);
|
2022-05-17 05:18:07 -05:00
|
|
|
}
|
|
|
|
Some(())
|
|
|
|
},
|
2022-05-30 06:51:48 -05:00
|
|
|
ast::Item(it) => match it {
|
|
|
|
// FIXME: record impl lifetimes so they aren't being reused in assoc item lifetime inlay hints
|
|
|
|
ast::Item::Impl(_) => None,
|
2022-12-16 10:13:46 -06:00
|
|
|
ast::Item::Fn(it) => fn_lifetime_fn::hints(hints, config, it),
|
2022-05-30 06:51:48 -05:00
|
|
|
// static type elisions
|
2022-12-16 10:13:46 -06:00
|
|
|
ast::Item::Static(it) => implicit_static::hints(hints, config, Either::Left(it)),
|
|
|
|
ast::Item::Const(it) => implicit_static::hints(hints, config, Either::Right(it)),
|
2022-05-30 06:51:48 -05:00
|
|
|
_ => None,
|
|
|
|
},
|
|
|
|
// FIXME: fn-ptr type, dyn fn type, and trait object type elisions
|
|
|
|
ast::Type(_) => None,
|
|
|
|
_ => None,
|
2022-05-14 07:26:08 -05:00
|
|
|
}
|
2022-05-17 05:18:07 -05:00
|
|
|
};
|
2019-07-19 16:20:09 -05:00
|
|
|
}
|
|
|
|
|
2022-12-01 09:39:57 -06:00
|
|
|
/// Checks if the type is an Iterator from std::iter and returns its item type.
|
2020-10-06 12:07:34 -05:00
|
|
|
fn hint_iterator(
|
2022-07-20 08:02:08 -05:00
|
|
|
sema: &Semantics<'_, RootDatabase>,
|
|
|
|
famous_defs: &FamousDefs<'_, '_>,
|
2020-10-07 06:14:12 -05:00
|
|
|
ty: &hir::Type,
|
2022-12-01 09:39:57 -06:00
|
|
|
) -> Option<hir::Type> {
|
2020-10-06 14:05:57 -05:00
|
|
|
let db = sema.db;
|
2021-05-05 15:55:12 -05:00
|
|
|
let strukt = ty.strip_references().as_adt()?;
|
2021-05-23 18:42:06 -05:00
|
|
|
let krate = strukt.module(db).krate();
|
2020-10-20 10:38:21 -05:00
|
|
|
if krate != famous_defs.core()? {
|
2020-10-06 12:07:34 -05:00
|
|
|
return None;
|
|
|
|
}
|
2020-10-20 10:38:21 -05:00
|
|
|
let iter_trait = famous_defs.core_iter_Iterator()?;
|
|
|
|
let iter_mod = famous_defs.core_iter()?;
|
2021-05-23 11:50:23 -05:00
|
|
|
|
|
|
|
// Assert that this struct comes from `core::iter`.
|
2021-07-20 09:19:02 -05:00
|
|
|
if !(strukt.visibility(db) == hir::Visibility::Public
|
|
|
|
&& strukt.module(db).path_to_root(db).contains(&iter_mod))
|
|
|
|
{
|
|
|
|
return None;
|
|
|
|
}
|
2021-05-23 11:50:23 -05:00
|
|
|
|
2020-10-06 12:07:34 -05:00
|
|
|
if ty.impls_trait(db, iter_trait, &[]) {
|
|
|
|
let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
|
2020-10-07 06:14:12 -05:00
|
|
|
hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
|
2020-10-06 12:07:34 -05:00
|
|
|
_ => None,
|
|
|
|
})?;
|
2021-04-03 14:50:52 -05:00
|
|
|
if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
|
2022-12-01 09:39:57 -06:00
|
|
|
return Some(ty);
|
2020-10-06 12:07:34 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2022-05-15 06:17:52 -05:00
|
|
|
fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
|
|
|
|
matches!(closure.body(), Some(ast::Expr::BlockExpr(_)))
|
|
|
|
}
|
|
|
|
|
2019-07-19 16:20:09 -05:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2022-12-20 06:45:31 -06:00
|
|
|
use expect_test::Expect;
|
2022-03-18 12:11:16 -05:00
|
|
|
use itertools::Itertools;
|
2020-06-30 11:04:25 -05:00
|
|
|
use test_utils::extract_annotations;
|
2019-07-19 16:20:09 -05:00
|
|
|
|
2022-11-04 11:11:15 -05:00
|
|
|
use crate::inlay_hints::AdjustmentHints;
|
2022-03-19 13:01:19 -05:00
|
|
|
use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
|
2020-06-30 11:04:25 -05:00
|
|
|
|
2022-05-28 07:13:25 -05:00
|
|
|
use super::ClosureReturnTypeHints;
|
|
|
|
|
2022-12-20 06:45:31 -06:00
|
|
|
pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
|
2022-12-21 09:24:49 -06:00
|
|
|
location_links: false,
|
2022-03-16 15:16:55 -05:00
|
|
|
render_colons: false,
|
|
|
|
type_hints: false,
|
|
|
|
parameter_hints: false,
|
|
|
|
chaining_hints: false,
|
2022-03-19 13:01:19 -05:00
|
|
|
lifetime_elision_hints: LifetimeElisionHints::Never,
|
2022-05-28 07:13:25 -05:00
|
|
|
closure_return_type_hints: ClosureReturnTypeHints::Never,
|
2022-11-07 05:49:52 -06:00
|
|
|
adjustment_hints: AdjustmentHints::Never,
|
2022-12-21 12:18:12 -06:00
|
|
|
adjustment_hints_hide_outside_unsafe: false,
|
2022-05-14 07:26:08 -05:00
|
|
|
binding_mode_hints: false,
|
|
|
|
hide_named_constructor_hints: false,
|
2022-05-15 06:17:52 -05:00
|
|
|
hide_closure_initialization_hints: false,
|
2022-03-19 12:11:56 -05:00
|
|
|
param_names_for_lifetime_elision_hints: false,
|
2022-03-16 15:16:55 -05:00
|
|
|
max_length: None,
|
2022-05-13 12:42:59 -05:00
|
|
|
closing_brace_hints_min_lines: None,
|
2022-03-16 15:16:55 -05:00
|
|
|
};
|
2022-12-21 09:24:49 -06:00
|
|
|
pub(super) const DISABLED_CONFIG_WITH_LINKS: InlayHintsConfig =
|
|
|
|
InlayHintsConfig { location_links: true, ..DISABLED_CONFIG };
|
2022-12-20 06:45:31 -06:00
|
|
|
pub(super) const TEST_CONFIG: InlayHintsConfig = InlayHintsConfig {
|
2021-01-06 04:54:28 -06:00
|
|
|
type_hints: true,
|
|
|
|
parameter_hints: true,
|
|
|
|
chaining_hints: true,
|
2022-05-28 07:13:25 -05:00
|
|
|
closure_return_type_hints: ClosureReturnTypeHints::WithBlock,
|
2022-05-14 07:26:08 -05:00
|
|
|
binding_mode_hints: true,
|
2022-03-19 13:01:19 -05:00
|
|
|
lifetime_elision_hints: LifetimeElisionHints::Always,
|
2022-12-21 09:24:49 -06:00
|
|
|
..DISABLED_CONFIG_WITH_LINKS
|
2021-01-06 04:54:28 -06:00
|
|
|
};
|
|
|
|
|
2021-10-03 08:31:35 -05:00
|
|
|
#[track_caller]
|
2022-12-20 06:45:31 -06:00
|
|
|
pub(super) fn check(ra_fixture: &str) {
|
2021-01-06 04:54:28 -06:00
|
|
|
check_with_config(TEST_CONFIG, ra_fixture);
|
2020-06-30 11:04:25 -05:00
|
|
|
}
|
|
|
|
|
2021-10-03 08:31:35 -05:00
|
|
|
#[track_caller]
|
2022-12-20 06:45:31 -06:00
|
|
|
pub(super) fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) {
|
2021-10-16 06:32:55 -05:00
|
|
|
let (analysis, file_id) = fixture::file(ra_fixture);
|
2022-03-18 12:11:16 -05:00
|
|
|
let mut expected = extract_annotations(&*analysis.file_text(file_id).unwrap());
|
2022-02-11 16:48:01 -06:00
|
|
|
let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
|
2022-03-18 12:11:16 -05:00
|
|
|
let actual = inlay_hints
|
|
|
|
.into_iter()
|
|
|
|
.map(|it| (it.range, it.label.to_string()))
|
|
|
|
.sorted_by_key(|(range, _)| range.start())
|
|
|
|
.collect::<Vec<_>>();
|
|
|
|
expected.sort_by_key(|(range, _)| range.start());
|
|
|
|
|
2020-07-16 14:51:44 -05:00
|
|
|
assert_eq!(expected, actual, "\nExpected:\n{:#?}\n\nActual:\n{:#?}", expected, actual);
|
2020-06-30 11:04:25 -05:00
|
|
|
}
|
2019-12-07 12:14:01 -06:00
|
|
|
|
2021-10-03 08:31:35 -05:00
|
|
|
#[track_caller]
|
2022-12-20 06:45:31 -06:00
|
|
|
pub(super) fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) {
|
2021-10-16 06:32:55 -05:00
|
|
|
let (analysis, file_id) = fixture::file(ra_fixture);
|
2022-02-11 16:48:01 -06:00
|
|
|
let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
|
2020-06-30 14:55:21 -05:00
|
|
|
expect.assert_debug_eq(&inlay_hints)
|
|
|
|
}
|
|
|
|
|
2020-03-10 02:55:46 -05:00
|
|
|
#[test]
|
2021-06-04 06:47:39 -05:00
|
|
|
fn hints_disabled() {
|
2020-06-30 11:04:25 -05:00
|
|
|
check_with_config(
|
2022-03-16 15:16:55 -05:00
|
|
|
InlayHintsConfig { render_colons: true, ..DISABLED_CONFIG },
|
2020-03-10 02:55:46 -05:00
|
|
|
r#"
|
2020-06-30 11:04:25 -05:00
|
|
|
fn foo(a: i32, b: i32) -> i32 { a + b }
|
2021-06-04 06:47:39 -05:00
|
|
|
fn main() {
|
|
|
|
let _x = foo(4, 4);
|
|
|
|
}"#,
|
|
|
|
);
|
|
|
|
}
|
2019-07-19 16:20:09 -05:00
|
|
|
}
|