Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion crates/ide/src/display/navigation_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -28,6 +28,7 @@ pub enum SymbolKind {
ValueParam,
SelfParam,
Local,
Label,
Function,
Const,
Static,
Expand Down Expand Up @@ -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)),
}
}
}
Expand Down Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion crates/ide/src/doc_links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down
15 changes: 15 additions & 0 deletions crates/ide/src/goto_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<|>;
}
}
}"#,
)
}
}
2 changes: 1 addition & 1 deletion crates/ide/src/hover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
24 changes: 23 additions & 1 deletion crates/ide/src/references.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};

Expand Down Expand Up @@ -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
"#]],
);
}
}
25 changes: 25 additions & 0 deletions crates/ide/src/references/rename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
"#,
)
}
}
19 changes: 15 additions & 4 deletions crates/ide/src/syntax_highlighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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()
}
Expand Down
1 change: 1 addition & 0 deletions crates/ide/src/syntax_highlighting/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 ; }
Expand Down
1 change: 1 addition & 0 deletions crates/ide/src/syntax_highlighting/tags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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 ; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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 ; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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 ; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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 ; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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 ; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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 ; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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 ; }
Expand Down Expand Up @@ -194,6 +195,11 @@
<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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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 ; }
Expand Down
5 changes: 5 additions & 0 deletions crates/ide/src/syntax_highlighting/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,11 @@ fn main() {
let baz = -baz;

let _ = !true;

'foo: loop {
break 'foo;
continue 'foo;
}
}

enum Option<T> {
Expand Down
18 changes: 13 additions & 5 deletions crates/ide_db/src/defs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand All @@ -26,7 +26,7 @@ pub enum Definition {
Local(Local),
TypeParam(TypeParam),
LifetimeParam(LifetimeParam),
// FIXME: Label
Label(Label),
}

impl Definition {
Expand All @@ -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)),
}
}

Expand All @@ -51,6 +52,7 @@ impl Definition {
Definition::Local(_) => None,
Definition::TypeParam(_) => None,
Definition::LifetimeParam(_) => None,
Definition::Label(_) => None,
}
}

Expand All @@ -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)
}
Expand Down Expand Up @@ -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,
}
}
Expand Down Expand Up @@ -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
Expand All @@ -387,7 +396,6 @@ impl NameRefClass {
.map(Definition::LifetimeParam)
.map(NameRefClass::Definition)
}
SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => None,
_ => None,
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/rust-analyzer/src/semantic_tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
4 changes: 3 additions & 1 deletion crates/rust-analyzer/src/to_proto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
}
Expand Down Expand Up @@ -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,
Expand Down