Auto merge of #13832 - Veykril:discriminant-hints, r=Veykril

Enum variant discriminants hints

![image](https://user-images.githubusercontent.com/3757771/209320042-eced617a-9a47-4808-ac23-916f469dc90c.png)
This commit is contained in:
bors 2023-01-02 13:20:33 +00:00
commit 17cc78f169
8 changed files with 217 additions and 2 deletions

View file

@ -24,12 +24,14 @@ mod chaining;
mod param_name;
mod binding_mode;
mod bind_pat;
mod discrimant;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct InlayHintsConfig {
pub location_links: bool,
pub render_colons: bool,
pub type_hints: bool,
pub discriminant_hints: DiscriminantHints,
pub parameter_hints: bool,
pub chaining_hints: bool,
pub adjustment_hints: AdjustmentHints,
@ -51,6 +53,13 @@ pub enum ClosureReturnTypeHints {
Never,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DiscriminantHints {
Always,
Never,
Fieldless,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum LifetimeElisionHints {
Always,
@ -76,6 +85,7 @@ pub enum InlayKind {
LifetimeHint,
ParameterHint,
TypeHint,
DiscriminantHint,
OpeningParenthesis,
ClosingParenthesis,
}
@ -365,6 +375,9 @@ fn hints(
ast::Item::Const(it) => implicit_static::hints(hints, config, Either::Right(it)),
_ => None,
},
ast::Variant(v) => {
discrimant::hints(hints, famous_defs, config, file_id, &v)
},
// FIXME: fn-ptr type, dyn fn type, and trait object type elisions
ast::Type(_) => None,
_ => None,
@ -418,12 +431,14 @@ mod tests {
use test_utils::extract_annotations;
use crate::inlay_hints::AdjustmentHints;
use crate::DiscriminantHints;
use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
use super::ClosureReturnTypeHints;
pub(super) const DISABLED_CONFIG: InlayHintsConfig = InlayHintsConfig {
location_links: false,
discriminant_hints: DiscriminantHints::Never,
render_colons: false,
type_hints: false,
parameter_hints: false,

View file

@ -0,0 +1,142 @@
//! Implementation of "enum variant discriminant" inlay hints:
//! ```no_run
//! enum Foo {
//! Bar/* = 0*/,
//! }
//! ```
use ide_db::{base_db::FileId, famous_defs::FamousDefs};
use syntax::ast::{self, AstNode, HasName};
use crate::{DiscriminantHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip};
pub(super) fn hints(
acc: &mut Vec<InlayHint>,
FamousDefs(sema, _): &FamousDefs<'_, '_>,
config: &InlayHintsConfig,
_: FileId,
variant: &ast::Variant,
) -> Option<()> {
let field_list = match config.discriminant_hints {
DiscriminantHints::Always => variant.field_list(),
DiscriminantHints::Fieldless => match variant.field_list() {
Some(_) => return None,
None => None,
},
DiscriminantHints::Never => return None,
};
if variant.eq_token().is_some() {
return None;
}
let name = variant.name()?;
let descended = sema.descend_node_into_attributes(variant.clone()).pop();
let desc_pat = descended.as_ref().unwrap_or(variant);
let v = sema.to_def(desc_pat)?;
let d = v.eval(sema.db);
acc.push(InlayHint {
range: match field_list {
Some(field_list) => name.syntax().text_range().cover(field_list.syntax().text_range()),
None => name.syntax().text_range(),
},
kind: InlayKind::DiscriminantHint,
label: match &d {
Ok(v) => format!("{}", v).into(),
Err(_) => "?".into(),
},
tooltip: Some(InlayTooltip::String(match &d {
Ok(_) => "enum variant discriminant".into(),
Err(e) => format!("{e:?}").into(),
})),
});
Some(())
}
#[cfg(test)]
mod tests {
use crate::inlay_hints::{
tests::{check_with_config, DISABLED_CONFIG},
DiscriminantHints, InlayHintsConfig,
};
#[track_caller]
fn check_discriminants(ra_fixture: &str) {
check_with_config(
InlayHintsConfig { discriminant_hints: DiscriminantHints::Always, ..DISABLED_CONFIG },
ra_fixture,
);
}
#[track_caller]
fn check_discriminants_fieldless(ra_fixture: &str) {
check_with_config(
InlayHintsConfig {
discriminant_hints: DiscriminantHints::Fieldless,
..DISABLED_CONFIG
},
ra_fixture,
);
}
#[test]
fn fieldless() {
check_discriminants(
r#"
enum Enum {
Variant,
//^^^^^^^0
Variant1,
//^^^^^^^^1
Variant2,
//^^^^^^^^2
Variant5 = 5,
Variant6,
//^^^^^^^^6
}
"#,
);
}
#[test]
fn datacarrying_mixed() {
check_discriminants(
r#"
enum Enum {
Variant(),
//^^^^^^^^^0
Variant1,
//^^^^^^^^1
Variant2 {},
//^^^^^^^^^^^2
Variant3,
//^^^^^^^^3
Variant5 = 5,
Variant6,
//^^^^^^^^6
}
"#,
);
}
#[test]
fn datacarrying_mixed_fieldless_set() {
check_discriminants_fieldless(
r#"
enum Enum {
Variant(),
Variant1,
//^^^^^^^^1
Variant2 {},
Variant3,
//^^^^^^^^3
Variant5 = 5,
Variant6,
//^^^^^^^^6
}
"#,
);
}
}

View file

@ -81,8 +81,8 @@ pub use crate::{
highlight_related::{HighlightRelatedConfig, HighlightedRange},
hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
inlay_hints::{
AdjustmentHints, ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig,
InlayKind, InlayTooltip, LifetimeElisionHints,
AdjustmentHints, ClosureReturnTypeHints, DiscriminantHints, InlayHint, InlayHintLabel,
InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
},
join_lines::JoinLinesConfig,
markup::Markup,

View file

@ -108,6 +108,7 @@ impl StaticIndex<'_> {
&InlayHintsConfig {
location_links: true,
render_colons: true,
discriminant_hints: crate::DiscriminantHints::Fieldless,
type_hints: true,
parameter_hints: true,
chaining_hints: true,

View file

@ -327,6 +327,8 @@ config_data! {
inlayHints_closingBraceHints_minLines: usize = "25",
/// Whether to show inlay type hints for return types of closures.
inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef = "\"never\"",
/// Whether to show enum variant discriminant hints.
inlayHints_discriminantHints_enable: DiscriminantHintsDef = "\"never\"",
/// Whether to show inlay hints for type adjustments.
inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
/// Whether to hide inlay hints for type adjustments outside of `unsafe` blocks.
@ -1218,6 +1220,11 @@ impl Config {
type_hints: self.data.inlayHints_typeHints_enable,
parameter_hints: self.data.inlayHints_parameterHints_enable,
chaining_hints: self.data.inlayHints_chainingHints_enable,
discriminant_hints: match self.data.inlayHints_discriminantHints_enable {
DiscriminantHintsDef::Always => ide::DiscriminantHints::Always,
DiscriminantHintsDef::Never => ide::DiscriminantHints::Never,
DiscriminantHintsDef::Fieldless => ide::DiscriminantHints::Fieldless,
},
closure_return_type_hints: match self.data.inlayHints_closureReturnTypeHints_enable {
ClosureReturnTypeHintsDef::Always => ide::ClosureReturnTypeHints::Always,
ClosureReturnTypeHintsDef::Never => ide::ClosureReturnTypeHints::Never,
@ -1579,6 +1586,7 @@ mod de_unit_v {
named_unit_variant!(skip_trivial);
named_unit_variant!(mutable);
named_unit_variant!(reborrow);
named_unit_variant!(fieldless);
named_unit_variant!(with_block);
}
@ -1742,6 +1750,17 @@ enum AdjustmentHintsDef {
Reborrow,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(untagged)]
enum DiscriminantHintsDef {
#[serde(deserialize_with = "true_or_always")]
Always,
#[serde(deserialize_with = "false_or_never")]
Never,
#[serde(deserialize_with = "de_unit_v::fieldless")]
Fieldless,
}
#[derive(Deserialize, Debug, Clone)]
#[serde(rename_all = "snake_case")]
enum FilesWatcherDef {
@ -2064,6 +2083,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
"Only show auto borrow and dereference adjustment hints."
]
},
"DiscriminantHintsDef" => set! {
"type": "string",
"enum": [
"always",
"never",
"fieldless"
],
"enumDescriptions": [
"Always show all discriminant hints.",
"Never show discriminant hints.",
"Only show discriminant hints on fieldless enum variants."
]
},
"CargoFeaturesDef" => set! {
"anyOf": [
{

View file

@ -434,6 +434,7 @@ pub(crate) fn inlay_hint(
InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"),
InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "),
InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "),
InlayKind::DiscriminantHint => inlay_hint.label.prepend_str(" = "),
_ => {}
}
@ -447,6 +448,7 @@ pub(crate) fn inlay_hint(
// after annotated thing
InlayKind::ClosureReturnTypeHint
| InlayKind::TypeHint
| InlayKind::DiscriminantHint
| InlayKind::ChainingHint
| InlayKind::GenericParamListHint
| InlayKind::ClosingParenthesis
@ -457,6 +459,7 @@ pub(crate) fn inlay_hint(
InlayKind::TypeHint => !render_colons,
InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true,
InlayKind::ClosingParenthesis
| InlayKind::DiscriminantHint
| InlayKind::OpeningParenthesis
| InlayKind::BindingModeHint
| InlayKind::ClosureReturnTypeHint
@ -473,6 +476,7 @@ pub(crate) fn inlay_hint(
| InlayKind::GenericParamListHint
| InlayKind::AdjustmentHint
| InlayKind::TypeHint
| InlayKind::DiscriminantHint
| InlayKind::ClosingBraceHint => false,
InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
@ -483,6 +487,7 @@ pub(crate) fn inlay_hint(
Some(lsp_types::InlayHintKind::TYPE)
}
InlayKind::ClosingParenthesis
| InlayKind::DiscriminantHint
| InlayKind::OpeningParenthesis
| InlayKind::BindingModeHint
| InlayKind::GenericParamListHint

View file

@ -454,6 +454,11 @@ to always show them).
--
Whether to show inlay type hints for return types of closures.
--
[[rust-analyzer.inlayHints.discriminantHints.enable]]rust-analyzer.inlayHints.discriminantHints.enable (default: `"never"`)::
+
--
Whether to show enum variant discriminant hints.
--
[[rust-analyzer.inlayHints.expressionAdjustmentHints.enable]]rust-analyzer.inlayHints.expressionAdjustmentHints.enable (default: `"never"`)::
+
--

View file

@ -960,6 +960,21 @@
"Only show type hints for return types of closures with blocks."
]
},
"rust-analyzer.inlayHints.discriminantHints.enable": {
"markdownDescription": "Whether to show enum variant discriminant hints.",
"default": "never",
"type": "string",
"enum": [
"always",
"never",
"fieldless"
],
"enumDescriptions": [
"Always show all discriminant hints.",
"Never show discriminant hints.",
"Only show discriminant hints on fieldless enum variants."
]
},
"rust-analyzer.inlayHints.expressionAdjustmentHints.enable": {
"markdownDescription": "Whether to show inlay hints for type adjustments.",
"default": "never",