mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-11-16 17:58:16 +00:00
Merge #7030
7030: Support labels in reference search r=matklad a=Veykril Implements general navigation for labels, goto def, rename and gives labels their own semantic highlighting class. Fixes #6966 Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
581419fd78
21 changed files with 142 additions and 14 deletions
|
@ -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);
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -1130,4 +1130,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<|>;
|
||||
}
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1540,4 +1540,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
"#,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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 ; }
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 ; }
|
||||
|
|
|
@ -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 ; }
|
||||
|
|
|
@ -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 ; }
|
||||
|
|
|
@ -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 ; }
|
||||
|
|
|
@ -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 ; }
|
||||
|
|
|
@ -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 ; }
|
||||
|
|
|
@ -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"><</span><span class="type_param declaration">T</span><span class="punctuation">></span> <span class="punctuation">{</span>
|
||||
|
|
|
@ -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 ; }
|
||||
|
|
|
@ -168,6 +168,11 @@ fn main() {
|
|||
let baz = -baz;
|
||||
|
||||
let _ = !true;
|
||||
|
||||
'foo: loop {
|
||||
break 'foo;
|
||||
continue 'foo;
|
||||
}
|
||||
}
|
||||
|
||||
enum Option<T> {
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
|
||||
|
||||
use hir::{
|
||||
db::HirDatabase, Crate, Field, HasVisibility, Impl, LifetimeParam, Local, MacroDef, Module,
|
||||
ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility,
|
||||
db::HirDatabase, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef,
|
||||
Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility,
|
||||
};
|
||||
use syntax::{
|
||||
ast::{self, AstNode},
|
||||
|
@ -26,7 +26,7 @@ pub enum Definition {
|
|||
Local(Local),
|
||||
TypeParam(TypeParam),
|
||||
LifetimeParam(LifetimeParam),
|
||||
// FIXME: Label
|
||||
Label(Label),
|
||||
}
|
||||
|
||||
impl Definition {
|
||||
|
@ -39,6 +39,7 @@ impl Definition {
|
|||
Definition::Local(it) => Some(it.module(db)),
|
||||
Definition::TypeParam(it) => Some(it.module(db)),
|
||||
Definition::LifetimeParam(it) => Some(it.module(db)),
|
||||
Definition::Label(it) => Some(it.module(db)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -51,6 +52,7 @@ impl Definition {
|
|||
Definition::Local(_) => None,
|
||||
Definition::TypeParam(_) => None,
|
||||
Definition::LifetimeParam(_) => None,
|
||||
Definition::Label(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,6 +79,7 @@ impl Definition {
|
|||
Definition::Local(it) => it.name(db)?,
|
||||
Definition::TypeParam(it) => it.name(db),
|
||||
Definition::LifetimeParam(it) => it.name(db),
|
||||
Definition::Label(it) => it.name(db),
|
||||
};
|
||||
Some(name)
|
||||
}
|
||||
|
@ -248,7 +251,10 @@ impl NameClass {
|
|||
let def = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::LifetimeParam(def)))
|
||||
},
|
||||
ast::Label(_it) => None,
|
||||
ast::Label(it) => {
|
||||
let def = sema.to_def(&it)?;
|
||||
Some(NameClass::Definition(Definition::Label(def)))
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -370,6 +376,9 @@ impl NameRefClass {
|
|||
let _p = profile::span("classify_lifetime_ref").detail(|| lifetime.to_string());
|
||||
let parent = lifetime.syntax().parent()?;
|
||||
match parent.kind() {
|
||||
SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {
|
||||
sema.resolve_label(lifetime).map(Definition::Label).map(NameRefClass::Definition)
|
||||
}
|
||||
SyntaxKind::LIFETIME_ARG
|
||||
| SyntaxKind::SELF_PARAM
|
||||
| SyntaxKind::TYPE_BOUND
|
||||
|
@ -387,7 +396,6 @@ impl NameRefClass {
|
|||
.map(Definition::LifetimeParam)
|
||||
.map(NameRefClass::Definition)
|
||||
}
|
||||
SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ define_semantic_token_types![
|
|||
(FORMAT_SPECIFIER, "formatSpecifier"),
|
||||
(GENERIC, "generic"),
|
||||
(LIFETIME, "lifetime"),
|
||||
(LABEL, "label"),
|
||||
(PUNCTUATION, "punctuation"),
|
||||
(SELF_KEYWORD, "selfKeyword"),
|
||||
(TYPE_ALIAS, "typeAlias"),
|
||||
|
|
|
@ -46,7 +46,8 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
|
|||
SymbolKind::Local
|
||||
| SymbolKind::SelfParam
|
||||
| SymbolKind::LifetimeParam
|
||||
| SymbolKind::ValueParam => lsp_types::SymbolKind::Variable,
|
||||
| SymbolKind::ValueParam
|
||||
| SymbolKind::Label => lsp_types::SymbolKind::Variable,
|
||||
SymbolKind::Union => lsp_types::SymbolKind::Struct,
|
||||
}
|
||||
}
|
||||
|
@ -378,6 +379,7 @@ fn semantic_token_type_and_modifiers(
|
|||
SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY,
|
||||
SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
|
||||
SymbolKind::LifetimeParam => semantic_tokens::LIFETIME,
|
||||
SymbolKind::Label => semantic_tokens::LABEL,
|
||||
SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER,
|
||||
SymbolKind::SelfParam => semantic_tokens::SELF_KEYWORD,
|
||||
SymbolKind::Local => lsp_types::SemanticTokenType::VARIABLE,
|
||||
|
|
Loading…
Reference in a new issue