Support labels in reference search

This commit is contained in:
Lukas Wirth 2020-12-23 17:15:01 +01:00
parent e1acb0ca5c
commit 42e3f97c30
21 changed files with 142 additions and 14 deletions

View file

@ -5,7 +5,7 @@ use std::fmt;
use either::Either;
use hir::{AssocItem, Documentation, FieldSource, HasAttrs, HasSource, InFile, ModuleSource};
use ide_db::{
base_db::{FileId, SourceDatabase},
base_db::{FileId, FileRange, SourceDatabase},
symbol_index::FileSymbolKind,
};
use ide_db::{defs::Definition, RootDatabase};
@ -28,6 +28,7 @@ pub enum SymbolKind {
ValueParam,
SelfParam,
Local,
Label,
Function,
Const,
Static,
@ -223,6 +224,7 @@ impl TryToNav for Definition {
Definition::Local(it) => Some(it.to_nav(db)),
Definition::TypeParam(it) => Some(it.to_nav(db)),
Definition::LifetimeParam(it) => Some(it.to_nav(db)),
Definition::Label(it) => Some(it.to_nav(db)),
}
}
}
@ -421,6 +423,27 @@ impl ToNav for hir::Local {
}
}
impl ToNav for hir::Label {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
let src = self.source(db);
let node = src.value.syntax();
let FileRange { file_id, range } = src.with_value(node).original_file_range(db);
let focus_range =
src.value.lifetime().and_then(|lt| lt.lifetime_ident_token()).map(|lt| lt.text_range());
let name = self.name(db).to_string().into();
NavigationTarget {
file_id,
name,
kind: Some(SymbolKind::Label),
full_range: range,
focus_range,
container_name: None,
description: None,
docs: None,
}
}
}
impl ToNav for hir::TypeParam {
fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
let src = self.source(db);

View file

@ -193,7 +193,8 @@ fn rewrite_intra_doc_link(
Definition::SelfType(_)
| Definition::Local(_)
| Definition::TypeParam(_)
| Definition::LifetimeParam(_) => return None,
| Definition::LifetimeParam(_)
| Definition::Label(_) => return None,
}?;
let krate = resolved.module(db)?.krate();
let canonical_path = resolved.canonical_path(db)?;

View file

@ -1105,4 +1105,19 @@ fn foo<T>() where T: for<'a> Foo<&'a<|> (u8, u16)>, {}
"#,
);
}
#[test]
fn goto_label() {
check(
r#"
fn foo<'foo>(_: &'foo ()) {
'foo: {
//^^^^
'bar: loop {
break 'foo<|>;
}
}
}"#,
)
}
}

View file

@ -370,7 +370,7 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
Adt::Enum(it) => from_def_source(db, it, mod_path),
})
}
Definition::TypeParam(_) | Definition::LifetimeParam(_) => {
Definition::TypeParam(_) | Definition::LifetimeParam(_) | Definition::Label(_) => {
// FIXME: Hover for generic param
None
}

View file

@ -130,7 +130,7 @@ pub(crate) fn find_all_refs(
kind = ReferenceKind::FieldShorthandForLocal;
}
}
} else if let Definition::LifetimeParam(_) = def {
} else if matches!(def, Definition::LifetimeParam(_) | Definition::Label(_)) {
kind = ReferenceKind::Lifetime;
};
@ -1122,4 +1122,26 @@ fn main() {
"#]],
);
}
#[test]
fn test_find_labels() {
check(
r#"
fn foo<'a>() -> &'a () {
'a: loop {
'b: loop {
continue 'a<|>;
}
break 'a;
}
}
"#,
expect![[r#"
'a Label FileId(0) 29..32 29..31 Lifetime
FileId(0) 80..82 Lifetime
FileId(0) 108..110 Lifetime
"#]],
);
}
}

View file

@ -1523,4 +1523,29 @@ fn main() {
}"#,
);
}
#[test]
fn test_rename_label() {
check(
"'foo",
r#"
fn foo<'a>() -> &'a () {
'a: {
'b: loop {
break 'a<|>;
}
}
}
"#,
r#"
fn foo<'a>() -> &'a () {
'foo: {
'b: loop {
break 'foo;
}
}
}
"#,
)
}
}

View file

@ -560,10 +560,20 @@ fn highlight_element(
CHAR => HighlightTag::CharLiteral.into(),
QUESTION => Highlight::new(HighlightTag::Operator) | HighlightModifier::ControlFlow,
LIFETIME => {
let h = Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam));
match element.parent().map(|it| it.kind()) {
Some(LIFETIME_PARAM) | Some(LABEL) => h | HighlightModifier::Definition,
_ => h,
let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap();
match NameClass::classify_lifetime(sema, &lifetime) {
Some(NameClass::Definition(def)) => {
highlight_def(db, def) | HighlightModifier::Definition
}
None => match NameRefClass::classify_lifetime(sema, &lifetime) {
Some(NameRefClass::Definition(def)) => highlight_def(db, def),
_ => Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam)),
},
_ => {
Highlight::new(HighlightTag::Symbol(SymbolKind::LifetimeParam))
| HighlightModifier::Definition
}
}
}
p if p.is_punct() => match p {
@ -825,6 +835,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
return h;
}
Definition::LifetimeParam(_) => HighlightTag::Symbol(SymbolKind::LifetimeParam),
Definition::Label(_) => HighlightTag::Symbol(SymbolKind::Label),
}
.into()
}

View file

@ -64,6 +64,7 @@ body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.label { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.documentation { color: #629755; }
.injected { opacity: 0.65 ; }

View file

@ -80,6 +80,7 @@ impl HighlightTag {
SymbolKind::LifetimeParam => "lifetime",
SymbolKind::Macro => "macro",
SymbolKind::Local => "variable",
SymbolKind::Label => "label",
SymbolKind::ValueParam => "value_param",
SymbolKind::SelfParam => "self_keyword",
SymbolKind::Impl => "self_type",

View file

@ -4,6 +4,7 @@ body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.label { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.documentation { color: #629755; }
.injected { opacity: 0.65 ; }

View file

@ -4,6 +4,7 @@ body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.label { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.documentation { color: #629755; }
.injected { opacity: 0.65 ; }

View file

@ -4,6 +4,7 @@ body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.label { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.documentation { color: #629755; }
.injected { opacity: 0.65 ; }

View file

@ -4,6 +4,7 @@ body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.label { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.documentation { color: #629755; }
.injected { opacity: 0.65 ; }

View file

@ -4,6 +4,7 @@ body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.label { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.documentation { color: #629755; }
.injected { opacity: 0.65 ; }

View file

@ -4,6 +4,7 @@ body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.label { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.documentation { color: #629755; }
.injected { opacity: 0.65 ; }

View file

@ -4,6 +4,7 @@ body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.label { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.documentation { color: #629755; }
.injected { opacity: 0.65 ; }
@ -194,6 +195,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="punctuation">;</span>
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="punctuation">;</span>
<span class="label declaration">'foo</span><span class="punctuation">:</span> <span class="keyword control">loop</span> <span class="punctuation">{</span>
<span class="keyword control">break</span> <span class="label">'foo</span><span class="punctuation">;</span>
<span class="keyword control">continue</span> <span class="label">'foo</span><span class="punctuation">;</span>
<span class="punctuation">}</span>
<span class="punctuation">}</span>
<span class="keyword">enum</span> <span class="enum declaration">Option</span><span class="punctuation">&lt;</span><span class="type_param declaration">T</span><span class="punctuation">&gt;</span> <span class="punctuation">{</span>

View file

@ -4,6 +4,7 @@ body { margin: 0; }
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
.lifetime { color: #DFAF8F; font-style: italic; }
.label { color: #DFAF8F; font-style: italic; }
.comment { color: #7F9F7F; }
.documentation { color: #629755; }
.injected { opacity: 0.65 ; }

View file

@ -168,6 +168,11 @@ fn main() {
let baz = -baz;
let _ = !true;
'foo: loop {
break 'foo;
continue 'foo;
}
}
enum Option<T> {