aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_assists/src/handlers/add_from_impl_for_enum.rs70
-rw-r--r--crates/ra_assists/src/handlers/replace_if_let_with_match.rs78
-rw-r--r--crates/ra_assists/src/handlers/replace_let_with_if_let.rs16
-rw-r--r--crates/ra_assists/src/handlers/replace_unwrap_with_match.rs52
-rw-r--r--crates/ra_assists/src/marks.rs1
-rw-r--r--crates/ra_assists/src/utils.rs110
-rw-r--r--crates/ra_flycheck/Cargo.toml2
-rw-r--r--crates/ra_hir/src/code_model.rs27
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs113
-rw-r--r--crates/ra_hir_ty/src/lib.rs12
-rw-r--r--crates/ra_hir_ty/src/lower.rs42
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs33
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs30
-rw-r--r--crates/ra_hir_ty/src/utils.rs48
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs38
-rw-r--r--crates/ra_ide/src/completion/complete_unqualified_path.rs12
-rw-r--r--crates/ra_ide/src/completion/presentation.rs46
-rw-r--r--crates/ra_ide/src/snapshots/highlight_injection.html1
-rw-r--r--crates/ra_ide/src/snapshots/highlight_strings.html71
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html1
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html1
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs2
-rw-r--r--crates/ra_ide/src/syntax_highlighting/html.rs1
-rw-r--r--crates/ra_ide/src/syntax_highlighting/tags.rs2
-rw-r--r--crates/ra_prof/src/hprof.rs45
-rw-r--r--crates/ra_syntax/src/ast.rs15
-rw-r--r--crates/ra_syntax/src/ast/make.rs3
-rw-r--r--crates/ra_syntax/src/ast/tokens.rs17
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/conv.rs6
-rw-r--r--crates/rust-analyzer/src/main_loop/handlers.rs49
-rw-r--r--crates/rust-analyzer/src/req.rs15
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs115
-rw-r--r--crates/rust-analyzer/tests/heavy_tests/main.rs27
34 files changed, 772 insertions, 331 deletions
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
index 03806724a..49deb6701 100644
--- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
+++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs
@@ -1,11 +1,12 @@
1use ra_ide_db::RootDatabase;
1use ra_syntax::{ 2use ra_syntax::{
2 ast::{self, AstNode, NameOwner}, 3 ast::{self, AstNode, NameOwner},
3 TextSize, 4 TextSize,
4}; 5};
5use stdx::format_to; 6use stdx::format_to;
6 7
7use crate::{Assist, AssistCtx, AssistId}; 8use crate::{utils::FamousDefs, Assist, AssistCtx, AssistId};
8use ra_ide_db::RootDatabase; 9use test_utils::tested_by;
9 10
10// Assist add_from_impl_for_enum 11// Assist add_from_impl_for_enum
11// 12//
@@ -41,7 +42,8 @@ pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> {
41 _ => return None, 42 _ => return None,
42 }; 43 };
43 44
44 if already_has_from_impl(ctx.sema, &variant) { 45 if existing_from_impl(ctx.sema, &variant).is_some() {
46 tested_by!(test_add_from_impl_already_exists);
45 return None; 47 return None;
46 } 48 }
47 49
@@ -70,41 +72,33 @@ impl From<{0}> for {1} {{
70 ) 72 )
71} 73}
72 74
73fn already_has_from_impl( 75fn existing_from_impl(
74 sema: &'_ hir::Semantics<'_, RootDatabase>, 76 sema: &'_ hir::Semantics<'_, RootDatabase>,
75 variant: &ast::EnumVariant, 77 variant: &ast::EnumVariant,
76) -> bool { 78) -> Option<()> {
77 let scope = sema.scope(&variant.syntax()); 79 let variant = sema.to_def(variant)?;
80 let enum_ = variant.parent_enum(sema.db);
81 let krate = enum_.module(sema.db).krate();
78 82
79 let from_path = ast::make::path_from_text("From"); 83 let from_trait = FamousDefs(sema, krate).core_convert_From()?;
80 let from_hir_path = match hir::Path::from_ast(from_path) {
81 Some(p) => p,
82 None => return false,
83 };
84 let from_trait = match scope.resolve_hir_path(&from_hir_path) {
85 Some(hir::PathResolution::Def(hir::ModuleDef::Trait(t))) => t,
86 _ => return false,
87 };
88 84
89 let e: hir::Enum = match sema.to_def(&variant.parent_enum()) { 85 let enum_type = enum_.ty(sema.db);
90 Some(e) => e,
91 None => return false,
92 };
93 let e_ty = e.ty(sema.db);
94 86
95 let hir_enum_var: hir::EnumVariant = match sema.to_def(variant) { 87 let wrapped_type = variant.fields(sema.db).get(0)?.signature_ty(sema.db);
96 Some(ev) => ev,
97 None => return false,
98 };
99 let var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db);
100 88
101 e_ty.impls_trait(sema.db, from_trait, &[var_ty]) 89 if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) {
90 Some(())
91 } else {
92 None
93 }
102} 94}
103 95
104#[cfg(test)] 96#[cfg(test)]
105mod tests { 97mod tests {
106 use super::*; 98 use super::*;
99
107 use crate::helpers::{check_assist, check_assist_not_applicable}; 100 use crate::helpers::{check_assist, check_assist_not_applicable};
101 use test_utils::covers;
108 102
109 #[test] 103 #[test]
110 fn test_add_from_impl_for_enum() { 104 fn test_add_from_impl_for_enum() {
@@ -136,36 +130,40 @@ mod tests {
136 ); 130 );
137 } 131 }
138 132
133 fn check_not_applicable(ra_fixture: &str) {
134 let fixture =
135 format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE);
136 check_assist_not_applicable(add_from_impl_for_enum, &fixture)
137 }
138
139 #[test] 139 #[test]
140 fn test_add_from_impl_no_element() { 140 fn test_add_from_impl_no_element() {
141 check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One }"); 141 check_not_applicable("enum A { <|>One }");
142 } 142 }
143 143
144 #[test] 144 #[test]
145 fn test_add_from_impl_more_than_one_element_in_tuple() { 145 fn test_add_from_impl_more_than_one_element_in_tuple() {
146 check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One(u32, String) }"); 146 check_not_applicable("enum A { <|>One(u32, String) }");
147 } 147 }
148 148
149 #[test] 149 #[test]
150 fn test_add_from_impl_struct_variant() { 150 fn test_add_from_impl_struct_variant() {
151 check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One { x: u32 } }"); 151 check_not_applicable("enum A { <|>One { x: u32 } }");
152 } 152 }
153 153
154 #[test] 154 #[test]
155 fn test_add_from_impl_already_exists() { 155 fn test_add_from_impl_already_exists() {
156 check_assist_not_applicable( 156 covers!(test_add_from_impl_already_exists);
157 add_from_impl_for_enum, 157 check_not_applicable(
158 r#"enum A { <|>One(u32), } 158 r#"
159enum A { <|>One(u32), }
159 160
160impl From<u32> for A { 161impl From<u32> for A {
161 fn from(v: u32) -> Self { 162 fn from(v: u32) -> Self {
162 A::One(v) 163 A::One(v)
163 } 164 }
164} 165}
165 166"#,
166pub trait From<T> {
167 fn from(T) -> Self;
168}"#,
169 ); 167 );
170 } 168 }
171 169
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
index 0a0a88f3d..9841f6980 100644
--- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs
@@ -1,11 +1,10 @@
1use ra_fmt::unwrap_trivial_block; 1use ra_fmt::unwrap_trivial_block;
2use ra_syntax::{ 2use ra_syntax::{
3 ast::{self, make}, 3 ast::{self, edit::IndentLevel, make},
4 AstNode, 4 AstNode,
5}; 5};
6 6
7use crate::{Assist, AssistCtx, AssistId}; 7use crate::{utils::TryEnum, Assist, AssistCtx, AssistId};
8use ast::edit::IndentLevel;
9 8
10// Assist: replace_if_let_with_match 9// Assist: replace_if_let_with_match
11// 10//
@@ -44,15 +43,21 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> {
44 ast::ElseBranch::IfExpr(_) => return None, 43 ast::ElseBranch::IfExpr(_) => return None,
45 }; 44 };
46 45
47 ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", |edit| { 46 let sema = ctx.sema;
47 ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", move |edit| {
48 let match_expr = { 48 let match_expr = {
49 let then_arm = { 49 let then_arm = {
50 let then_expr = unwrap_trivial_block(then_block); 50 let then_expr = unwrap_trivial_block(then_block);
51 make::match_arm(vec![pat], then_expr) 51 make::match_arm(vec![pat.clone()], then_expr)
52 }; 52 };
53 let else_arm = { 53 let else_arm = {
54 let pattern = sema
55 .type_of_pat(&pat)
56 .and_then(|ty| TryEnum::from_ty(sema, &ty))
57 .map(|it| it.sad_pattern())
58 .unwrap_or_else(|| make::placeholder_pat().into());
54 let else_expr = unwrap_trivial_block(else_block); 59 let else_expr = unwrap_trivial_block(else_block);
55 make::match_arm(vec![make::placeholder_pat().into()], else_expr) 60 make::match_arm(vec![pattern], else_expr)
56 }; 61 };
57 make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) 62 make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm]))
58 }; 63 };
@@ -68,6 +73,7 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> {
68#[cfg(test)] 73#[cfg(test)]
69mod tests { 74mod tests {
70 use super::*; 75 use super::*;
76
71 use crate::helpers::{check_assist, check_assist_target}; 77 use crate::helpers::{check_assist, check_assist_target};
72 78
73 #[test] 79 #[test]
@@ -145,4 +151,64 @@ impl VariantData {
145 }", 151 }",
146 ); 152 );
147 } 153 }
154
155 #[test]
156 fn special_case_option() {
157 check_assist(
158 replace_if_let_with_match,
159 r#"
160enum Option<T> { Some(T), None }
161use Option::*;
162
163fn foo(x: Option<i32>) {
164 <|>if let Some(x) = x {
165 println!("{}", x)
166 } else {
167 println!("none")
168 }
169}
170 "#,
171 r#"
172enum Option<T> { Some(T), None }
173use Option::*;
174
175fn foo(x: Option<i32>) {
176 <|>match x {
177 Some(x) => println!("{}", x),
178 None => println!("none"),
179 }
180}
181 "#,
182 );
183 }
184
185 #[test]
186 fn special_case_result() {
187 check_assist(
188 replace_if_let_with_match,
189 r#"
190enum Result<T, E> { Ok(T), Err(E) }
191use Result::*;
192
193fn foo(x: Result<i32, ()>) {
194 <|>if let Ok(x) = x {
195 println!("{}", x)
196 } else {
197 println!("none")
198 }
199}
200 "#,
201 r#"
202enum Result<T, E> { Ok(T), Err(E) }
203use Result::*;
204
205fn foo(x: Result<i32, ()>) {
206 <|>match x {
207 Ok(x) => println!("{}", x),
208 Err(_) => println!("none"),
209 }
210}
211 "#,
212 );
213 }
148} 214}
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
index bdbaae389..0cf23b754 100644
--- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
+++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs
@@ -1,6 +1,5 @@
1use std::iter::once; 1use std::iter::once;
2 2
3use hir::Adt;
4use ra_syntax::{ 3use ra_syntax::{
5 ast::{ 4 ast::{
6 self, 5 self,
@@ -12,6 +11,7 @@ use ra_syntax::{
12 11
13use crate::{ 12use crate::{
14 assist_ctx::{Assist, AssistCtx}, 13 assist_ctx::{Assist, AssistCtx},
14 utils::TryEnum,
15 AssistId, 15 AssistId,
16}; 16};
17 17
@@ -45,20 +45,10 @@ pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> {
45 let init = let_stmt.initializer()?; 45 let init = let_stmt.initializer()?;
46 let original_pat = let_stmt.pat()?; 46 let original_pat = let_stmt.pat()?;
47 let ty = ctx.sema.type_of_expr(&init)?; 47 let ty = ctx.sema.type_of_expr(&init)?;
48 let enum_ = match ty.as_adt() { 48 let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case());
49 Some(Adt::Enum(it)) => it,
50 _ => return None,
51 };
52 let happy_case =
53 [("Result", "Ok"), ("Option", "Some")].iter().find_map(|(known_type, happy_case)| {
54 if &enum_.name(ctx.db).to_string() == known_type {
55 return Some(happy_case);
56 }
57 None
58 });
59 49
60 ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| { 50 ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| {
61 let with_placeholder: ast::Pat = match happy_case { 51 let with_placeholder: ast::Pat = match happy_variant {
62 None => make::placeholder_pat().into(), 52 None => make::placeholder_pat().into(),
63 Some(var_name) => make::tuple_struct_pat( 53 Some(var_name) => make::tuple_struct_pat(
64 make::path_unqualified(make::path_segment(make::name_ref(var_name))), 54 make::path_unqualified(make::path_segment(make::name_ref(var_name))),
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
index 62cb7a763..62d4ea522 100644
--- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
+++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs
@@ -1,12 +1,11 @@
1use std::iter; 1use std::iter;
2 2
3use ra_syntax::{ 3use ra_syntax::{
4 ast::{self, make}, 4 ast::{self, edit::IndentLevel, make},
5 AstNode, 5 AstNode,
6}; 6};
7 7
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{utils::TryEnum, Assist, AssistCtx, AssistId};
9use ast::edit::IndentLevel;
10 9
11// Assist: replace_unwrap_with_match 10// Assist: replace_unwrap_with_match
12// 11//
@@ -38,42 +37,27 @@ pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> {
38 } 37 }
39 let caller = method_call.expr()?; 38 let caller = method_call.expr()?;
40 let ty = ctx.sema.type_of_expr(&caller)?; 39 let ty = ctx.sema.type_of_expr(&caller)?;
40 let happy_variant = TryEnum::from_ty(ctx.sema, &ty)?.happy_case();
41 41
42 let type_name = ty.as_adt()?.name(ctx.sema.db).to_string(); 42 ctx.add_assist(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", |edit| {
43 let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant)));
44 let it = make::bind_pat(make::name("a")).into();
45 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
43 46
44 for (unwrap_type, variant_name) in [("Result", "Ok"), ("Option", "Some")].iter() { 47 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a")));
45 if &type_name == unwrap_type { 48 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path));
46 return ctx.add_assist(
47 AssistId("replace_unwrap_with_match"),
48 "Replace unwrap with match",
49 |edit| {
50 let ok_path =
51 make::path_unqualified(make::path_segment(make::name_ref(variant_name)));
52 let it = make::bind_pat(make::name("a")).into();
53 let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into();
54 49
55 let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); 50 let unreachable_call = make::unreachable_macro_call().into();
56 let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); 51 let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call);
57 52
58 let unreachable_call = make::unreachable_macro_call().into(); 53 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]);
59 let err_arm = make::match_arm( 54 let match_expr = make::expr_match(caller.clone(), match_arm_list);
60 iter::once(make::placeholder_pat().into()), 55 let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr);
61 unreachable_call,
62 );
63 56
64 let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); 57 edit.target(method_call.syntax().text_range());
65 let match_expr = make::expr_match(caller.clone(), match_arm_list); 58 edit.set_cursor(caller.syntax().text_range().start());
66 let match_expr = 59 edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
67 IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); 60 })
68
69 edit.target(method_call.syntax().text_range());
70 edit.set_cursor(caller.syntax().text_range().start());
71 edit.replace_ast::<ast::Expr>(method_call.into(), match_expr);
72 },
73 );
74 }
75 }
76 None
77} 61}
78 62
79#[cfg(test)] 63#[cfg(test)]
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs
index 6c2a2b8b6..8d910205f 100644
--- a/crates/ra_assists/src/marks.rs
+++ b/crates/ra_assists/src/marks.rs
@@ -8,4 +8,5 @@ test_utils::marks![
8 test_not_inline_mut_variable 8 test_not_inline_mut_variable
9 test_not_applicable_if_variable_unused 9 test_not_applicable_if_variable_unused
10 change_visibility_field_false_positive 10 change_visibility_field_false_positive
11 test_add_from_impl_already_exists
11]; 12];
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs
index 3d6c59bda..efd988697 100644
--- a/crates/ra_assists/src/utils.rs
+++ b/crates/ra_assists/src/utils.rs
@@ -1,7 +1,9 @@
1//! Assorted functions shared by several assists. 1//! Assorted functions shared by several assists.
2pub(crate) mod insert_use; 2pub(crate) mod insert_use;
3 3
4use hir::Semantics; 4use std::iter;
5
6use hir::{Adt, Crate, Semantics, Trait, Type};
5use ra_ide_db::RootDatabase; 7use ra_ide_db::RootDatabase;
6use ra_syntax::{ 8use ra_syntax::{
7 ast::{self, make, NameOwner}, 9 ast::{self, make, NameOwner},
@@ -99,3 +101,109 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
99 _ => None, 101 _ => None,
100 } 102 }
101} 103}
104
105#[derive(Clone, Copy)]
106pub(crate) enum TryEnum {
107 Result,
108 Option,
109}
110
111impl TryEnum {
112 const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
113
114 pub(crate) fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> {
115 let enum_ = match ty.as_adt() {
116 Some(Adt::Enum(it)) => it,
117 _ => return None,
118 };
119 TryEnum::ALL.iter().find_map(|&var| {
120 if &enum_.name(sema.db).to_string() == var.type_name() {
121 return Some(var);
122 }
123 None
124 })
125 }
126
127 pub(crate) fn happy_case(self) -> &'static str {
128 match self {
129 TryEnum::Result => "Ok",
130 TryEnum::Option => "Some",
131 }
132 }
133
134 pub(crate) fn sad_pattern(self) -> ast::Pat {
135 match self {
136 TryEnum::Result => make::tuple_struct_pat(
137 make::path_unqualified(make::path_segment(make::name_ref("Err"))),
138 iter::once(make::placeholder_pat().into()),
139 )
140 .into(),
141 TryEnum::Option => make::bind_pat(make::name("None")).into(),
142 }
143 }
144
145 fn type_name(self) -> &'static str {
146 match self {
147 TryEnum::Result => "Result",
148 TryEnum::Option => "Option",
149 }
150 }
151}
152
153/// Helps with finding well-know things inside the standard library. This is
154/// somewhat similar to the known paths infra inside hir, but it different; We
155/// want to make sure that IDE specific paths don't become interesting inside
156/// the compiler itself as well.
157pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, pub(crate) Crate);
158
159#[allow(non_snake_case)]
160impl FamousDefs<'_, '_> {
161 #[cfg(test)]
162 pub(crate) const FIXTURE: &'static str = r#"
163//- /libcore.rs crate:core
164pub mod convert{
165 pub trait From<T> {
166 fn from(T) -> Self;
167 }
168}
169
170pub mod prelude { pub use crate::convert::From }
171#[prelude_import]
172pub use prelude::*;
173"#;
174
175 pub(crate) fn core_convert_From(&self) -> Option<Trait> {
176 self.find_trait("core:convert:From")
177 }
178
179 fn find_trait(&self, path: &str) -> Option<Trait> {
180 let db = self.0.db;
181 let mut path = path.split(':');
182 let trait_ = path.next_back()?;
183 let std_crate = path.next()?;
184 let std_crate = self
185 .1
186 .dependencies(db)
187 .into_iter()
188 .find(|dep| &dep.name.to_string() == std_crate)?
189 .krate;
190
191 let mut module = std_crate.root_module(db)?;
192 for segment in path {
193 module = module.children(db).find_map(|child| {
194 let name = child.name(db)?;
195 if &name.to_string() == segment {
196 Some(child)
197 } else {
198 None
199 }
200 })?;
201 }
202 let def =
203 module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1;
204 match def {
205 hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
206 _ => None,
207 }
208 }
209}
diff --git a/crates/ra_flycheck/Cargo.toml b/crates/ra_flycheck/Cargo.toml
index 76e5cada4..324c33d9d 100644
--- a/crates/ra_flycheck/Cargo.toml
+++ b/crates/ra_flycheck/Cargo.toml
@@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8crossbeam-channel = "0.4.0" 8crossbeam-channel = "0.4.0"
9lsp-types = { version = "0.73.0", features = ["proposed"] } 9lsp-types = { version = "0.74.0", features = ["proposed"] }
10log = "0.4.8" 10log = "0.4.8"
11cargo_metadata = "0.9.1" 11cargo_metadata = "0.9.1"
12serde_json = "1.0.48" 12serde_json = "1.0.48"
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index fb788736d..3fb419571 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1157,18 +1157,21 @@ impl Type {
1157 1157
1158 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { 1158 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
1159 if let Ty::Apply(a_ty) = &self.ty.value { 1159 if let Ty::Apply(a_ty) = &self.ty.value {
1160 if let TypeCtor::Adt(AdtId::StructId(s)) = a_ty.ctor { 1160 let variant_id = match a_ty.ctor {
1161 let var_def = s.into(); 1161 TypeCtor::Adt(AdtId::StructId(s)) => s.into(),
1162 return db 1162 TypeCtor::Adt(AdtId::UnionId(u)) => u.into(),
1163 .field_types(var_def) 1163 _ => return Vec::new(),
1164 .iter() 1164 };
1165 .map(|(local_id, ty)| { 1165
1166 let def = Field { parent: var_def.into(), id: local_id }; 1166 return db
1167 let ty = ty.clone().subst(&a_ty.parameters); 1167 .field_types(variant_id)
1168 (def, self.derived(ty)) 1168 .iter()
1169 }) 1169 .map(|(local_id, ty)| {
1170 .collect(); 1170 let def = Field { parent: variant_id.into(), id: local_id };
1171 } 1171 let ty = ty.clone().subst(&a_ty.parameters);
1172 (def, self.derived(ty))
1173 })
1174 .collect();
1172 }; 1175 };
1173 Vec::new() 1176 Vec::new()
1174 } 1177 }
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
index bb45b0f1d..e60f879a3 100644
--- a/crates/ra_hir_expand/src/builtin_derive.rs
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -9,7 +9,7 @@ use ra_syntax::{
9}; 9};
10 10
11use crate::db::AstDatabase; 11use crate::db::AstDatabase;
12use crate::{name, quote, LazyMacroId, MacroDefId, MacroDefKind}; 12use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind};
13 13
14macro_rules! register_builtin { 14macro_rules! register_builtin {
15 ( $($trait:ident => $expand:ident),* ) => { 15 ( $($trait:ident => $expand:ident),* ) => {
@@ -153,76 +153,113 @@ fn expand_simple_derive(
153 Ok(expanded) 153 Ok(expanded)
154} 154}
155 155
156fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree {
157 // FIXME: make hygiene works for builtin derive macro
158 // such that $crate can be used here.
159
160 let m: MacroCallId = id.into();
161 let file_id = m.as_file().original_file(db);
162 let cg = db.crate_graph();
163 let krates = db.relevant_crates(file_id);
164 let krate = match krates.get(0) {
165 Some(krate) => krate,
166 None => {
167 let tt = quote! { core };
168 return tt.token_trees[0].clone();
169 }
170 };
171
172 // XXX
173 // All crates except core itself should have a dependency on core,
174 // We detect `core` by seeing whether it doesn't have such a dependency.
175 let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") {
176 quote! { core }
177 } else {
178 quote! { crate }
179 };
180
181 tt.token_trees[0].clone()
182}
183
156fn copy_expand( 184fn copy_expand(
157 _db: &dyn AstDatabase, 185 db: &dyn AstDatabase,
158 _id: LazyMacroId, 186 id: LazyMacroId,
159 tt: &tt::Subtree, 187 tt: &tt::Subtree,
160) -> Result<tt::Subtree, mbe::ExpandError> { 188) -> Result<tt::Subtree, mbe::ExpandError> {
161 expand_simple_derive(tt, quote! { std::marker::Copy }) 189 let krate = find_builtin_crate(db, id);
190 expand_simple_derive(tt, quote! { #krate::marker::Copy })
162} 191}
163 192
164fn clone_expand( 193fn clone_expand(
165 _db: &dyn AstDatabase, 194 db: &dyn AstDatabase,
166 _id: LazyMacroId, 195 id: LazyMacroId,
167 tt: &tt::Subtree, 196 tt: &tt::Subtree,
168) -> Result<tt::Subtree, mbe::ExpandError> { 197) -> Result<tt::Subtree, mbe::ExpandError> {
169 expand_simple_derive(tt, quote! { std::clone::Clone }) 198 let krate = find_builtin_crate(db, id);
199 expand_simple_derive(tt, quote! { #krate::clone::Clone })
170} 200}
171 201
172fn default_expand( 202fn default_expand(
173 _db: &dyn AstDatabase, 203 db: &dyn AstDatabase,
174 _id: LazyMacroId, 204 id: LazyMacroId,
175 tt: &tt::Subtree, 205 tt: &tt::Subtree,
176) -> Result<tt::Subtree, mbe::ExpandError> { 206) -> Result<tt::Subtree, mbe::ExpandError> {
177 expand_simple_derive(tt, quote! { std::default::Default }) 207 let krate = find_builtin_crate(db, id);
208 expand_simple_derive(tt, quote! { #krate::default::Default })
178} 209}
179 210
180fn debug_expand( 211fn debug_expand(
181 _db: &dyn AstDatabase, 212 db: &dyn AstDatabase,
182 _id: LazyMacroId, 213 id: LazyMacroId,
183 tt: &tt::Subtree, 214 tt: &tt::Subtree,
184) -> Result<tt::Subtree, mbe::ExpandError> { 215) -> Result<tt::Subtree, mbe::ExpandError> {
185 expand_simple_derive(tt, quote! { std::fmt::Debug }) 216 let krate = find_builtin_crate(db, id);
217 expand_simple_derive(tt, quote! { #krate::fmt::Debug })
186} 218}
187 219
188fn hash_expand( 220fn hash_expand(
189 _db: &dyn AstDatabase, 221 db: &dyn AstDatabase,
190 _id: LazyMacroId, 222 id: LazyMacroId,
191 tt: &tt::Subtree, 223 tt: &tt::Subtree,
192) -> Result<tt::Subtree, mbe::ExpandError> { 224) -> Result<tt::Subtree, mbe::ExpandError> {
193 expand_simple_derive(tt, quote! { std::hash::Hash }) 225 let krate = find_builtin_crate(db, id);
226 expand_simple_derive(tt, quote! { #krate::hash::Hash })
194} 227}
195 228
196fn eq_expand( 229fn eq_expand(
197 _db: &dyn AstDatabase, 230 db: &dyn AstDatabase,
198 _id: LazyMacroId, 231 id: LazyMacroId,
199 tt: &tt::Subtree, 232 tt: &tt::Subtree,
200) -> Result<tt::Subtree, mbe::ExpandError> { 233) -> Result<tt::Subtree, mbe::ExpandError> {
201 expand_simple_derive(tt, quote! { std::cmp::Eq }) 234 let krate = find_builtin_crate(db, id);
235 expand_simple_derive(tt, quote! { #krate::cmp::Eq })
202} 236}
203 237
204fn partial_eq_expand( 238fn partial_eq_expand(
205 _db: &dyn AstDatabase, 239 db: &dyn AstDatabase,
206 _id: LazyMacroId, 240 id: LazyMacroId,
207 tt: &tt::Subtree, 241 tt: &tt::Subtree,
208) -> Result<tt::Subtree, mbe::ExpandError> { 242) -> Result<tt::Subtree, mbe::ExpandError> {
209 expand_simple_derive(tt, quote! { std::cmp::PartialEq }) 243 let krate = find_builtin_crate(db, id);
244 expand_simple_derive(tt, quote! { #krate::cmp::PartialEq })
210} 245}
211 246
212fn ord_expand( 247fn ord_expand(
213 _db: &dyn AstDatabase, 248 db: &dyn AstDatabase,
214 _id: LazyMacroId, 249 id: LazyMacroId,
215 tt: &tt::Subtree, 250 tt: &tt::Subtree,
216) -> Result<tt::Subtree, mbe::ExpandError> { 251) -> Result<tt::Subtree, mbe::ExpandError> {
217 expand_simple_derive(tt, quote! { std::cmp::Ord }) 252 let krate = find_builtin_crate(db, id);
253 expand_simple_derive(tt, quote! { #krate::cmp::Ord })
218} 254}
219 255
220fn partial_ord_expand( 256fn partial_ord_expand(
221 _db: &dyn AstDatabase, 257 db: &dyn AstDatabase,
222 _id: LazyMacroId, 258 id: LazyMacroId,
223 tt: &tt::Subtree, 259 tt: &tt::Subtree,
224) -> Result<tt::Subtree, mbe::ExpandError> { 260) -> Result<tt::Subtree, mbe::ExpandError> {
225 expand_simple_derive(tt, quote! { std::cmp::PartialOrd }) 261 let krate = find_builtin_crate(db, id);
262 expand_simple_derive(tt, quote! { #krate::cmp::PartialOrd })
226} 263}
227 264
228#[cfg(test)] 265#[cfg(test)]
@@ -234,8 +271,18 @@ mod tests {
234 271
235 fn expand_builtin_derive(s: &str, name: Name) -> String { 272 fn expand_builtin_derive(s: &str, name: Name) -> String {
236 let def = find_builtin_derive(&name).unwrap(); 273 let def = find_builtin_derive(&name).unwrap();
274 let fixture = format!(
275 r#"//- /main.rs crate:main deps:core
276<|>
277{}
278//- /lib.rs crate:core
279// empty
280"#,
281 s
282 );
237 283
238 let (db, file_id) = TestDB::with_single_file(&s); 284 let (db, file_pos) = TestDB::with_position(&fixture);
285 let file_id = file_pos.file_id;
239 let parsed = db.parse(file_id); 286 let parsed = db.parse(file_id);
240 let items: Vec<_> = 287 let items: Vec<_> =
241 parsed.syntax_node().descendants().filter_map(ast::ModuleItem::cast).collect(); 288 parsed.syntax_node().descendants().filter_map(ast::ModuleItem::cast).collect();
@@ -264,7 +311,7 @@ mod tests {
264 known::Copy, 311 known::Copy,
265 ); 312 );
266 313
267 assert_eq!(expanded, "impl< >std::marker::CopyforFoo< >{}"); 314 assert_eq!(expanded, "impl< >core::marker::CopyforFoo< >{}");
268 } 315 }
269 316
270 #[test] 317 #[test]
@@ -279,7 +326,7 @@ mod tests {
279 326
280 assert_eq!( 327 assert_eq!(
281 expanded, 328 expanded,
282 "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}" 329 "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"
283 ); 330 );
284 } 331 }
285 332
@@ -297,7 +344,7 @@ mod tests {
297 344
298 assert_eq!( 345 assert_eq!(
299 expanded, 346 expanded,
300 "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}" 347 "impl<T0:core::marker::Copy,T1:core::marker::Copy>core::marker::CopyforFoo<T0,T1>{}"
301 ); 348 );
302 } 349 }
303 350
@@ -313,7 +360,7 @@ mod tests {
313 360
314 assert_eq!( 361 assert_eq!(
315 expanded, 362 expanded,
316 "impl<T0:std::clone::Clone,T1:std::clone::Clone>std::clone::CloneforFoo<T0,T1>{}" 363 "impl<T0:core::clone::Clone,T1:core::clone::Clone>core::clone::CloneforFoo<T0,T1>{}"
317 ); 364 );
318 } 365 }
319} 366}
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 279c06d65..a8ef32ec5 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -487,6 +487,18 @@ impl<T> Binders<T> {
487 pub fn new(num_binders: usize, value: T) -> Self { 487 pub fn new(num_binders: usize, value: T) -> Self {
488 Self { num_binders, value } 488 Self { num_binders, value }
489 } 489 }
490
491 pub fn as_ref(&self) -> Binders<&T> {
492 Binders { num_binders: self.num_binders, value: &self.value }
493 }
494
495 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> {
496 Binders { num_binders: self.num_binders, value: f(self.value) }
497 }
498
499 pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> {
500 Some(Binders { num_binders: self.num_binders, value: f(self.value)? })
501 }
490} 502}
491 503
492impl<T: Clone> Binders<&T> { 504impl<T: Clone> Binders<&T> {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index b57214296..a6f893037 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -28,11 +28,11 @@ use crate::{
28 db::HirDatabase, 28 db::HirDatabase,
29 primitive::{FloatTy, IntTy}, 29 primitive::{FloatTy, IntTy},
30 utils::{ 30 utils::{
31 all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice, 31 all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
32 variant_data, 32 make_mut_slice, variant_data,
33 }, 33 },
34 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, 34 Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate,
35 ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, 35 ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
36}; 36};
37 37
38#[derive(Debug)] 38#[derive(Debug)]
@@ -256,7 +256,7 @@ impl Ty {
256 if remaining_segments.len() == 1 { 256 if remaining_segments.len() == 1 {
257 // resolve unselected assoc types 257 // resolve unselected assoc types
258 let segment = remaining_segments.first().unwrap(); 258 let segment = remaining_segments.first().unwrap();
259 (Ty::select_associated_type(ctx, ty, res, segment), None) 259 (Ty::select_associated_type(ctx, res, segment), None)
260 } else if remaining_segments.len() > 1 { 260 } else if remaining_segments.len() > 1 {
261 // FIXME report error (ambiguous associated type) 261 // FIXME report error (ambiguous associated type)
262 (Ty::Unknown, None) 262 (Ty::Unknown, None)
@@ -380,21 +380,20 @@ impl Ty {
380 380
381 fn select_associated_type( 381 fn select_associated_type(
382 ctx: &TyLoweringContext<'_>, 382 ctx: &TyLoweringContext<'_>,
383 self_ty: Ty,
384 res: Option<TypeNs>, 383 res: Option<TypeNs>,
385 segment: PathSegment<'_>, 384 segment: PathSegment<'_>,
386 ) -> Ty { 385 ) -> Ty {
387 let traits_from_env: Vec<_> = match res { 386 let traits_from_env: Vec<_> = match res {
388 Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) { 387 Some(TypeNs::SelfType(impl_id)) => match ctx.db.impl_trait(impl_id) {
389 None => return Ty::Unknown, 388 None => return Ty::Unknown,
390 Some(trait_ref) => vec![trait_ref.value.trait_], 389 Some(trait_ref) => vec![trait_ref.value],
391 }, 390 },
392 Some(TypeNs::GenericParam(param_id)) => { 391 Some(TypeNs::GenericParam(param_id)) => {
393 let predicates = ctx.db.generic_predicates_for_param(param_id); 392 let predicates = ctx.db.generic_predicates_for_param(param_id);
394 let mut traits_: Vec<_> = predicates 393 let mut traits_: Vec<_> = predicates
395 .iter() 394 .iter()
396 .filter_map(|pred| match &pred.value { 395 .filter_map(|pred| match &pred.value {
397 GenericPredicate::Implemented(tr) => Some(tr.trait_), 396 GenericPredicate::Implemented(tr) => Some(tr.clone()),
398 _ => None, 397 _ => None,
399 }) 398 })
400 .collect(); 399 .collect();
@@ -404,20 +403,37 @@ impl Ty {
404 if generics.params.types[param_id.local_id].provenance 403 if generics.params.types[param_id.local_id].provenance
405 == TypeParamProvenance::TraitSelf 404 == TypeParamProvenance::TraitSelf
406 { 405 {
407 traits_.push(trait_id); 406 let trait_ref = TraitRef {
407 trait_: trait_id,
408 substs: Substs::bound_vars(&generics, DebruijnIndex::INNERMOST),
409 };
410 traits_.push(trait_ref);
408 } 411 }
409 } 412 }
410 traits_ 413 traits_
411 } 414 }
412 _ => return Ty::Unknown, 415 _ => return Ty::Unknown,
413 }; 416 };
414 let traits = traits_from_env.into_iter().flat_map(|t| all_super_traits(ctx.db.upcast(), t)); 417 let traits = traits_from_env.into_iter().flat_map(|t| all_super_trait_refs(ctx.db, t));
415 for t in traits { 418 for t in traits {
416 if let Some(associated_ty) = ctx.db.trait_data(t).associated_type_by_name(&segment.name) 419 if let Some(associated_ty) =
420 ctx.db.trait_data(t.trait_).associated_type_by_name(&segment.name)
417 { 421 {
418 let substs = 422 let substs = match ctx.type_param_mode {
419 Substs::build_for_def(ctx.db, t).push(self_ty).fill_with_unknown().build(); 423 TypeParamLoweringMode::Placeholder => {
420 // FIXME handle type parameters on the segment 424 // if we're lowering to placeholders, we have to put
425 // them in now
426 let s = Substs::type_params(
427 ctx.db,
428 ctx.resolver
429 .generic_def()
430 .expect("there should be generics if there's a generic param"),
431 );
432 t.substs.subst_bound_vars(&s)
433 }
434 TypeParamLoweringMode::Variable => t.substs,
435 };
436 // FIXME handle (forbid) type parameters on the segment
421 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs }); 437 return Ty::Projection(ProjectionTy { associated_ty, parameters: substs });
422 } 438 }
423 } 439 }
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
index 6b5267232..5ddecbdc6 100644
--- a/crates/ra_hir_ty/src/tests/macros.rs
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -622,14 +622,14 @@ fn main() {
622fn infer_derive_clone_simple() { 622fn infer_derive_clone_simple() {
623 let (db, pos) = TestDB::with_position( 623 let (db, pos) = TestDB::with_position(
624 r#" 624 r#"
625//- /main.rs crate:main deps:std 625//- /main.rs crate:main deps:core
626#[derive(Clone)] 626#[derive(Clone)]
627struct S; 627struct S;
628fn test() { 628fn test() {
629 S.clone()<|>; 629 S.clone()<|>;
630} 630}
631 631
632//- /lib.rs crate:std 632//- /lib.rs crate:core
633#[prelude_import] 633#[prelude_import]
634use clone::*; 634use clone::*;
635mod clone { 635mod clone {
@@ -643,10 +643,35 @@ mod clone {
643} 643}
644 644
645#[test] 645#[test]
646fn infer_derive_clone_in_core() {
647 let (db, pos) = TestDB::with_position(
648 r#"
649//- /lib.rs crate:core
650#[prelude_import]
651use clone::*;
652mod clone {
653 trait Clone {
654 fn clone(&self) -> Self;
655 }
656}
657#[derive(Clone)]
658pub struct S;
659
660//- /main.rs crate:main deps:core
661use core::S;
662fn test() {
663 S.clone()<|>;
664}
665"#,
666 );
667 assert_eq!("S", type_at_pos(&db, pos));
668}
669
670#[test]
646fn infer_derive_clone_with_params() { 671fn infer_derive_clone_with_params() {
647 let (db, pos) = TestDB::with_position( 672 let (db, pos) = TestDB::with_position(
648 r#" 673 r#"
649//- /main.rs crate:main deps:std 674//- /main.rs crate:main deps:core
650#[derive(Clone)] 675#[derive(Clone)]
651struct S; 676struct S;
652#[derive(Clone)] 677#[derive(Clone)]
@@ -656,7 +681,7 @@ fn test() {
656 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>; 681 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>;
657} 682}
658 683
659//- /lib.rs crate:std 684//- /lib.rs crate:core
660#[prelude_import] 685#[prelude_import]
661use clone::*; 686use clone::*;
662mod clone { 687mod clone {
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index f51cdd496..e555c879a 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1898,6 +1898,36 @@ fn test() {
1898} 1898}
1899 1899
1900#[test] 1900#[test]
1901fn unselected_projection_chalk_fold() {
1902 let t = type_at(
1903 r#"
1904//- /main.rs
1905trait Interner {}
1906trait Fold<I: Interner, TI = I> {
1907 type Result;
1908}
1909
1910struct Ty<I: Interner> {}
1911impl<I: Interner, TI: Interner> Fold<I, TI> for Ty<I> {
1912 type Result = Ty<TI>;
1913}
1914
1915fn fold<I: Interner, T>(interner: &I, t: T) -> T::Result
1916where
1917 T: Fold<I, I>,
1918{
1919 loop {}
1920}
1921
1922fn foo<I: Interner>(interner: &I, t: Ty<I>) {
1923 fold(interner, t)<|>;
1924}
1925"#,
1926 );
1927 assert_eq!(t, "Ty<I>");
1928}
1929
1930#[test]
1901fn trait_impl_self_ty() { 1931fn trait_impl_self_ty() {
1902 let t = type_at( 1932 let t = type_at(
1903 r#" 1933 r#"
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index 1e5022fa4..f98350bf9 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -14,6 +14,8 @@ use hir_def::{
14}; 14};
15use hir_expand::name::{name, Name}; 15use hir_expand::name::{name, Name};
16 16
17use crate::{db::HirDatabase, GenericPredicate, TraitRef};
18
17fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 19fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
18 let resolver = trait_.resolver(db); 20 let resolver = trait_.resolver(db);
19 // returning the iterator directly doesn't easily work because of 21 // returning the iterator directly doesn't easily work because of
@@ -41,6 +43,28 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
41 .collect() 43 .collect()
42} 44}
43 45
46fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<TraitRef> {
47 // returning the iterator directly doesn't easily work because of
48 // lifetime problems, but since there usually shouldn't be more than a
49 // few direct traits this should be fine (we could even use some kind of
50 // SmallVec if performance is a concern)
51 let generic_params = db.generic_params(trait_ref.trait_.into());
52 let trait_self = match generic_params.find_trait_self_param() {
53 Some(p) => TypeParamId { parent: trait_ref.trait_.into(), local_id: p },
54 None => return Vec::new(),
55 };
56 db.generic_predicates_for_param(trait_self)
57 .iter()
58 .filter_map(|pred| {
59 pred.as_ref().filter_map(|pred| match pred {
60 GenericPredicate::Implemented(tr) => Some(tr.clone()),
61 _ => None,
62 })
63 })
64 .map(|pred| pred.subst(&trait_ref.substs))
65 .collect()
66}
67
44/// Returns an iterator over the whole super trait hierarchy (including the 68/// Returns an iterator over the whole super trait hierarchy (including the
45/// trait itself). 69/// trait itself).
46pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 70pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
@@ -62,6 +86,30 @@ pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<Tra
62 result 86 result
63} 87}
64 88
89/// Given a trait ref (`Self: Trait`), builds all the implied trait refs for
90/// super traits. The original trait ref will be included. So the difference to
91/// `all_super_traits` is that we keep track of type parameters; for example if
92/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
93/// `Self: OtherTrait<i32>`.
94pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> {
95 // we need to take care a bit here to avoid infinite loops in case of cycles
96 // (i.e. if we have `trait A: B; trait B: A;`)
97 let mut result = vec![trait_ref];
98 let mut i = 0;
99 while i < result.len() {
100 let t = &result[i];
101 // yeah this is quadratic, but trait hierarchies should be flat
102 // enough that this doesn't matter
103 for tt in direct_super_trait_refs(db, t) {
104 if !result.iter().any(|tr| tr.trait_ == tt.trait_) {
105 result.push(tt);
106 }
107 }
108 i += 1;
109 }
110 result
111}
112
65/// Finds a path from a trait to one of its super traits. Returns an empty 113/// Finds a path from a trait to one of its super traits. Returns an empty
66/// vector if there is no path. 114/// vector if there is no path.
67pub(super) fn find_super_trait_path( 115pub(super) fn find_super_trait_path(
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index 814354ffa..05f825c6f 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -250,6 +250,44 @@ mod tests {
250 } 250 }
251 251
252 #[test] 252 #[test]
253 fn test_union_field_completion() {
254 assert_debug_snapshot!(
255 do_ref_completion(
256 r"
257 union Un {
258 field: u8,
259 other: u16,
260 }
261
262 fn foo(u: Un) {
263 u.<|>
264 }
265 ",
266 ),
267 @r###"
268 [
269 CompletionItem {
270 label: "field",
271 source_range: 140..140,
272 delete: 140..140,
273 insert: "field",
274 kind: Field,
275 detail: "u8",
276 },
277 CompletionItem {
278 label: "other",
279 source_range: 140..140,
280 delete: 140..140,
281 insert: "other",
282 kind: Field,
283 detail: "u16",
284 },
285 ]
286 "###
287 );
288 }
289
290 #[test]
253 fn test_method_completion() { 291 fn test_method_completion() {
254 assert_debug_snapshot!( 292 assert_debug_snapshot!(
255 do_ref_completion( 293 do_ref_completion(
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs
index f559f2b97..a6a5568de 100644
--- a/crates/ra_ide/src/completion/complete_unqualified_path.rs
+++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs
@@ -53,7 +53,7 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
53 // Variants with trivial paths are already added by the existing completion logic, 53 // Variants with trivial paths are already added by the existing completion logic,
54 // so we should avoid adding these twice 54 // so we should avoid adding these twice
55 if path.segments.len() > 1 { 55 if path.segments.len() > 1 {
56 acc.add_enum_variant(ctx, variant, Some(path.to_string())); 56 acc.add_qualified_enum_variant(ctx, variant, path);
57 } 57 }
58 } 58 }
59 } 59 }
@@ -1173,6 +1173,7 @@ mod tests {
1173 delete: 248..250, 1173 delete: 248..250,
1174 insert: "Foo::Bar", 1174 insert: "Foo::Bar",
1175 kind: EnumVariant, 1175 kind: EnumVariant,
1176 lookup: "Bar",
1176 detail: "()", 1177 detail: "()",
1177 }, 1178 },
1178 CompletionItem { 1179 CompletionItem {
@@ -1181,6 +1182,7 @@ mod tests {
1181 delete: 248..250, 1182 delete: 248..250,
1182 insert: "Foo::Baz", 1183 insert: "Foo::Baz",
1183 kind: EnumVariant, 1184 kind: EnumVariant,
1185 lookup: "Baz",
1184 detail: "()", 1186 detail: "()",
1185 }, 1187 },
1186 CompletionItem { 1188 CompletionItem {
@@ -1189,6 +1191,7 @@ mod tests {
1189 delete: 248..250, 1191 delete: 248..250,
1190 insert: "Foo::Quux", 1192 insert: "Foo::Quux",
1191 kind: EnumVariant, 1193 kind: EnumVariant,
1194 lookup: "Quux",
1192 detail: "()", 1195 detail: "()",
1193 }, 1196 },
1194 ] 1197 ]
@@ -1231,6 +1234,7 @@ mod tests {
1231 delete: 219..221, 1234 delete: 219..221,
1232 insert: "Foo::Bar", 1235 insert: "Foo::Bar",
1233 kind: EnumVariant, 1236 kind: EnumVariant,
1237 lookup: "Bar",
1234 detail: "()", 1238 detail: "()",
1235 }, 1239 },
1236 CompletionItem { 1240 CompletionItem {
@@ -1239,6 +1243,7 @@ mod tests {
1239 delete: 219..221, 1243 delete: 219..221,
1240 insert: "Foo::Baz", 1244 insert: "Foo::Baz",
1241 kind: EnumVariant, 1245 kind: EnumVariant,
1246 lookup: "Baz",
1242 detail: "()", 1247 detail: "()",
1243 }, 1248 },
1244 CompletionItem { 1249 CompletionItem {
@@ -1247,6 +1252,7 @@ mod tests {
1247 delete: 219..221, 1252 delete: 219..221,
1248 insert: "Foo::Quux", 1253 insert: "Foo::Quux",
1249 kind: EnumVariant, 1254 kind: EnumVariant,
1255 lookup: "Quux",
1250 detail: "()", 1256 detail: "()",
1251 }, 1257 },
1252 ] 1258 ]
@@ -1285,6 +1291,7 @@ mod tests {
1285 delete: 185..186, 1291 delete: 185..186,
1286 insert: "Foo::Bar", 1292 insert: "Foo::Bar",
1287 kind: EnumVariant, 1293 kind: EnumVariant,
1294 lookup: "Bar",
1288 detail: "()", 1295 detail: "()",
1289 }, 1296 },
1290 CompletionItem { 1297 CompletionItem {
@@ -1293,6 +1300,7 @@ mod tests {
1293 delete: 185..186, 1300 delete: 185..186,
1294 insert: "Foo::Baz", 1301 insert: "Foo::Baz",
1295 kind: EnumVariant, 1302 kind: EnumVariant,
1303 lookup: "Baz",
1296 detail: "()", 1304 detail: "()",
1297 }, 1305 },
1298 CompletionItem { 1306 CompletionItem {
@@ -1301,6 +1309,7 @@ mod tests {
1301 delete: 185..186, 1309 delete: 185..186,
1302 insert: "Foo::Quux", 1310 insert: "Foo::Quux",
1303 kind: EnumVariant, 1311 kind: EnumVariant,
1312 lookup: "Quux",
1304 detail: "()", 1313 detail: "()",
1305 }, 1314 },
1306 CompletionItem { 1315 CompletionItem {
@@ -1353,6 +1362,7 @@ mod tests {
1353 delete: 98..99, 1362 delete: 98..99,
1354 insert: "m::E::V", 1363 insert: "m::E::V",
1355 kind: EnumVariant, 1364 kind: EnumVariant,
1365 lookup: "V",
1356 detail: "()", 1366 detail: "()",
1357 }, 1367 },
1358 ] 1368 ]
diff --git a/crates/ra_ide/src/completion/presentation.rs b/crates/ra_ide/src/completion/presentation.rs
index 77d354376..2edb130cf 100644
--- a/crates/ra_ide/src/completion/presentation.rs
+++ b/crates/ra_ide/src/completion/presentation.rs
@@ -1,6 +1,6 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2 2
3use hir::{Docs, HasAttrs, HasSource, HirDisplay, ScopeDef, StructKind, Type}; 3use hir::{Docs, HasAttrs, HasSource, HirDisplay, ModPath, ScopeDef, StructKind, Type};
4use ra_syntax::ast::NameOwner; 4use ra_syntax::ast::NameOwner;
5use stdx::SepBy; 5use stdx::SepBy;
6use test_utils::tested_by; 6use test_utils::tested_by;
@@ -246,14 +246,37 @@ impl Completions {
246 .add_to(self); 246 .add_to(self);
247 } 247 }
248 248
249 pub(crate) fn add_qualified_enum_variant(
250 &mut self,
251 ctx: &CompletionContext,
252 variant: hir::EnumVariant,
253 path: ModPath,
254 ) {
255 self.add_enum_variant_impl(ctx, variant, None, Some(path))
256 }
257
249 pub(crate) fn add_enum_variant( 258 pub(crate) fn add_enum_variant(
250 &mut self, 259 &mut self,
251 ctx: &CompletionContext, 260 ctx: &CompletionContext,
252 variant: hir::EnumVariant, 261 variant: hir::EnumVariant,
253 local_name: Option<String>, 262 local_name: Option<String>,
254 ) { 263 ) {
264 self.add_enum_variant_impl(ctx, variant, local_name, None)
265 }
266
267 fn add_enum_variant_impl(
268 &mut self,
269 ctx: &CompletionContext,
270 variant: hir::EnumVariant,
271 local_name: Option<String>,
272 path: Option<ModPath>,
273 ) {
255 let is_deprecated = is_deprecated(variant, ctx.db); 274 let is_deprecated = is_deprecated(variant, ctx.db);
256 let name = local_name.unwrap_or_else(|| variant.name(ctx.db).to_string()); 275 let name = local_name.unwrap_or_else(|| variant.name(ctx.db).to_string());
276 let qualified_name = match &path {
277 Some(it) => it.to_string(),
278 None => name.to_string(),
279 };
257 let detail_types = variant 280 let detail_types = variant
258 .fields(ctx.db) 281 .fields(ctx.db)
259 .into_iter() 282 .into_iter()
@@ -271,16 +294,23 @@ impl Completions {
271 .surround_with("{ ", " }") 294 .surround_with("{ ", " }")
272 .to_string(), 295 .to_string(),
273 }; 296 };
274 let mut res = 297 let mut res = CompletionItem::new(
275 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone()) 298 CompletionKind::Reference,
276 .kind(CompletionItemKind::EnumVariant) 299 ctx.source_range(),
277 .set_documentation(variant.docs(ctx.db)) 300 qualified_name.clone(),
278 .set_deprecated(is_deprecated) 301 )
279 .detail(detail); 302 .kind(CompletionItemKind::EnumVariant)
303 .set_documentation(variant.docs(ctx.db))
304 .set_deprecated(is_deprecated)
305 .detail(detail);
306
307 if path.is_some() {
308 res = res.lookup_by(name);
309 }
280 310
281 if variant_kind == StructKind::Tuple { 311 if variant_kind == StructKind::Tuple {
282 let params = Params::Anonymous(variant.fields(ctx.db).len()); 312 let params = Params::Anonymous(variant.fields(ctx.db).len());
283 res = res.add_call_parens(ctx, name, params) 313 res = res.add_call_parens(ctx, qualified_name, params)
284 } 314 }
285 315
286 res.add_to(self); 316 res.add_to(self);
diff --git a/crates/ra_ide/src/snapshots/highlight_injection.html b/crates/ra_ide/src/snapshots/highlight_injection.html
index 6ec13bd80..ea026d7a0 100644
--- a/crates/ra_ide/src/snapshots/highlight_injection.html
+++ b/crates/ra_ide/src/snapshots/highlight_injection.html
@@ -20,6 +20,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
20.macro { color: #94BFF3; } 20.macro { color: #94BFF3; }
21.module { color: #AFD8AF; } 21.module { color: #AFD8AF; }
22.variable { color: #DCDCCC; } 22.variable { color: #DCDCCC; }
23.format_specifier { color: #CC696B; }
23.mutable { text-decoration: underline; } 24.mutable { text-decoration: underline; }
24 25
25.keyword { color: #F0DFAF; font-weight: bold; } 26.keyword { color: #F0DFAF; font-weight: bold; }
diff --git a/crates/ra_ide/src/snapshots/highlight_strings.html b/crates/ra_ide/src/snapshots/highlight_strings.html
index 433f2e0c5..de06daf72 100644
--- a/crates/ra_ide/src/snapshots/highlight_strings.html
+++ b/crates/ra_ide/src/snapshots/highlight_strings.html
@@ -20,6 +20,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
20.macro { color: #94BFF3; } 20.macro { color: #94BFF3; }
21.module { color: #AFD8AF; } 21.module { color: #AFD8AF; }
22.variable { color: #DCDCCC; } 22.variable { color: #DCDCCC; }
23.format_specifier { color: #CC696B; }
23.mutable { text-decoration: underline; } 24.mutable { text-decoration: underline; }
24 25
25.keyword { color: #F0DFAF; font-weight: bold; } 26.keyword { color: #F0DFAF; font-weight: bold; }
@@ -40,43 +41,43 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
40<span class="keyword">fn</span> <span class="function declaration">main</span>() { 41<span class="keyword">fn</span> <span class="function declaration">main</span>() {
41 <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> 42 <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span>
42 <span class="macro">println!</span>(<span class="string_literal">"Hello"</span>); <span class="comment">// =&gt; "Hello"</span> 43 <span class="macro">println!</span>(<span class="string_literal">"Hello"</span>); <span class="comment">// =&gt; "Hello"</span>
43 <span class="macro">println!</span>(<span class="string_literal">"Hello, </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>); <span class="comment">// =&gt; "Hello, world!"</span> 44 <span class="macro">println!</span>(<span class="string_literal">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>); <span class="comment">// =&gt; "Hello, world!"</span>
44 <span class="macro">println!</span>(<span class="string_literal">"The number is </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>); <span class="comment">// =&gt; "The number is 1"</span> 45 <span class="macro">println!</span>(<span class="string_literal">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>); <span class="comment">// =&gt; "The number is 1"</span>
45 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">?</span><span class="attribute">}</span><span class="string_literal">"</span>, (<span class="numeric_literal">3</span>, <span class="numeric_literal">4</span>)); <span class="comment">// =&gt; "(3, 4)"</span> 46 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal">"</span>, (<span class="numeric_literal">3</span>, <span class="numeric_literal">4</span>)); <span class="comment">// =&gt; "(3, 4)"</span>
46 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">value</span><span class="attribute">}</span><span class="string_literal">"</span>, value=<span class="numeric_literal">4</span>); <span class="comment">// =&gt; "4"</span> 47 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal">"</span>, value=<span class="numeric_literal">4</span>); <span class="comment">// =&gt; "4"</span>
47 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "1 2"</span> 48 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "1 2"</span>
48 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">42</span>); <span class="comment">// =&gt; "0042" with leading zerosV</span> 49 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">42</span>); <span class="comment">// =&gt; "0042" with leading zerosV</span>
49 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="numeric_literal">1</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="numeric_literal">0</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "2 1 1 2"</span> 50 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "2 1 1 2"</span>
50 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">argument</span><span class="attribute">}</span><span class="string_literal">"</span>, argument = <span class="string_literal">"test"</span>); <span class="comment">// =&gt; "test"</span> 51 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal">"</span>, argument = <span class="string_literal">"test"</span>); <span class="comment">// =&gt; "test"</span>
51 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">name</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, name = <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "2 1"</span> 52 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">1</span>, name = <span class="numeric_literal">2</span>); <span class="comment">// =&gt; "2 1"</span>
52 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">a</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="variable">c</span><span class="attribute">}</span><span class="string_literal"> </span><span class="attribute">{</span><span class="variable">b</span><span class="attribute">}</span><span class="string_literal">"</span>, a=<span class="string_literal">"a"</span>, b=<span class="char_literal">'b'</span>, c=<span class="numeric_literal">3</span>); <span class="comment">// =&gt; "a 3 b"</span> 53 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal">"</span>, a=<span class="string_literal">"a"</span>, b=<span class="char_literal">'b'</span>, c=<span class="numeric_literal">3</span>); <span class="comment">// =&gt; "a 3 b"</span>
53 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); 54 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
54 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">1</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>); 55 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>);
55 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="numeric_literal">1</span><span class="attribute">:</span><span class="numeric_literal">0</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>); 56 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>);
56 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="variable">width</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, width = <span class="numeric_literal">5</span>); 57 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>, width = <span class="numeric_literal">5</span>);
57 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">&lt;</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); 58 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
58 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">-</span><span class="attribute">&lt;</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); 59 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
59 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">^</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); 60 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
60 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">&gt;</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>); 61 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"x"</span>);
61 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">+</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); 62 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>);
62 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">#</span><span class="variable">x</span><span class="string_literal">}!"</span>, <span class="numeric_literal">27</span>); 63 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="string_literal">}!"</span>, <span class="numeric_literal">27</span>);
63 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>); 64 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">5</span>);
64 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">!"</span>, -<span class="numeric_literal">5</span>); 65 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, -<span class="numeric_literal">5</span>);
65 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>); 66 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="numeric_literal">27</span>);
66 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="numeric_literal">0</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="numeric_literal">1</span><span class="attribute">:</span><span class="attribute">.</span><span class="numeric_literal">5</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>); 67 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>);
67 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="numeric_literal">1</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="numeric_literal">2</span><span class="attribute">:</span><span class="attribute">.</span><span class="numeric_literal">0</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>); 68 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="numeric_literal">5</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">0.01</span>);
68 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="numeric_literal">0</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="numeric_literal">2</span><span class="attribute">:</span><span class="attribute">.</span><span class="numeric_literal">1</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>); 69 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>);
69 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="attribute">:</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>); 70 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>);
70 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="numeric_literal">2</span><span class="attribute">:</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>); 71 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, <span class="numeric_literal">5</span>, <span class="numeric_literal">0.01</span>);
71 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal"> is </span><span class="attribute">{</span><span class="variable">number</span><span class="attribute">:</span><span class="attribute">.</span><span class="variable">prec</span><span class="attribute">$</span><span class="attribute">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, prec = <span class="numeric_literal">5</span>, number = <span class="numeric_literal">0.01</span>); 72 <span class="macro">println!</span>(<span class="string_literal">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal">"</span>, <span class="string_literal">"x"</span>, prec = <span class="numeric_literal">5</span>, number = <span class="numeric_literal">0.01</span>);
72 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">, `</span><span class="attribute">{</span><span class="variable">name</span><span class="attribute">:</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">` has 3 fractional digits"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="numeric_literal">1234.56</span>); 73 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 fractional digits"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="numeric_literal">1234.56</span>);
73 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">, `</span><span class="attribute">{</span><span class="variable">name</span><span class="attribute">:</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">` has 3 characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>); 74 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>);
74 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">, `</span><span class="attribute">{</span><span class="variable">name</span><span class="attribute">:</span><span class="attribute">&gt;</span><span class="numeric_literal">8</span><span class="attribute">.</span><span class="attribute">*</span><span class="attribute">}</span><span class="string_literal">` has 3 right-aligned characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>); 75 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal">` has 3 right-aligned characters"</span>, <span class="string_literal">"Hello"</span>, <span class="numeric_literal">3</span>, name=<span class="string_literal">"1234.56"</span>);
75 <span class="macro">println!</span>(<span class="string_literal">"Hello {{}}"</span>); 76 <span class="macro">println!</span>(<span class="string_literal">"Hello {{}}"</span>);
76 <span class="macro">println!</span>(<span class="string_literal">"{{ Hello"</span>); 77 <span class="macro">println!</span>(<span class="string_literal">"{{ Hello"</span>);
77 78
78 <span class="macro">println!</span>(<span class="string_literal">r"Hello, </span><span class="attribute">{</span><span class="attribute">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>); 79 <span class="macro">println!</span>(<span class="string_literal">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal">!"</span>, <span class="string_literal">"world"</span>);
79 80
80 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">\x41</span><span class="attribute">}</span><span class="string_literal">"</span>, A = <span class="numeric_literal">92</span>); 81 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">\x41</span><span class="format_specifier">}</span><span class="string_literal">"</span>, A = <span class="numeric_literal">92</span>);
81 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="attribute">{</span><span class="variable">ничоси</span><span class="attribute">}</span><span class="string_literal">"</span>, ничоси = <span class="numeric_literal">92</span>); 82 <span class="macro">println!</span>(<span class="string_literal">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal">"</span>, ничоси = <span class="numeric_literal">92</span>);
82}</code></pre> \ No newline at end of file 83}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index ccb1fc751..4b12fe823 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -20,6 +20,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
20.macro { color: #94BFF3; } 20.macro { color: #94BFF3; }
21.module { color: #AFD8AF; } 21.module { color: #AFD8AF; }
22.variable { color: #DCDCCC; } 22.variable { color: #DCDCCC; }
23.format_specifier { color: #CC696B; }
23.mutable { text-decoration: underline; } 24.mutable { text-decoration: underline; }
24 25
25.keyword { color: #F0DFAF; font-weight: bold; } 26.keyword { color: #F0DFAF; font-weight: bold; }
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 3df82c45f..11e1f3e44 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -20,6 +20,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
20.macro { color: #94BFF3; } 20.macro { color: #94BFF3; }
21.module { color: #AFD8AF; } 21.module { color: #AFD8AF; }
22.variable { color: #DCDCCC; } 22.variable { color: #DCDCCC; }
23.format_specifier { color: #CC696B; }
23.mutable { text-decoration: underline; } 24.mutable { text-decoration: underline; }
24 25
25.keyword { color: #F0DFAF; font-weight: bold; } 26.keyword { color: #F0DFAF; font-weight: bold; }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index be0f8c827..6658c7bb2 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -290,7 +290,7 @@ fn highlight_format_specifier(kind: FormatSpecifier) -> Option<HighlightTag> {
290 | FormatSpecifier::DollarSign 290 | FormatSpecifier::DollarSign
291 | FormatSpecifier::Dot 291 | FormatSpecifier::Dot
292 | FormatSpecifier::Asterisk 292 | FormatSpecifier::Asterisk
293 | FormatSpecifier::QuestionMark => HighlightTag::Attribute, 293 | FormatSpecifier::QuestionMark => HighlightTag::FormatSpecifier,
294 FormatSpecifier::Integer | FormatSpecifier::Zero => HighlightTag::NumericLiteral, 294 FormatSpecifier::Integer | FormatSpecifier::Zero => HighlightTag::NumericLiteral,
295 FormatSpecifier::Identifier => HighlightTag::Local, 295 FormatSpecifier::Identifier => HighlightTag::Local,
296 }) 296 })
diff --git a/crates/ra_ide/src/syntax_highlighting/html.rs b/crates/ra_ide/src/syntax_highlighting/html.rs
index 010db4017..ff0eeeb52 100644
--- a/crates/ra_ide/src/syntax_highlighting/html.rs
+++ b/crates/ra_ide/src/syntax_highlighting/html.rs
@@ -79,6 +79,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
79.macro { color: #94BFF3; } 79.macro { color: #94BFF3; }
80.module { color: #AFD8AF; } 80.module { color: #AFD8AF; }
81.variable { color: #DCDCCC; } 81.variable { color: #DCDCCC; }
82.format_specifier { color: #CC696B; }
82.mutable { text-decoration: underline; } 83.mutable { text-decoration: underline; }
83 84
84.keyword { color: #F0DFAF; font-weight: bold; } 85.keyword { color: #F0DFAF; font-weight: bold; }
diff --git a/crates/ra_ide/src/syntax_highlighting/tags.rs b/crates/ra_ide/src/syntax_highlighting/tags.rs
index f2c421654..be1a0f12b 100644
--- a/crates/ra_ide/src/syntax_highlighting/tags.rs
+++ b/crates/ra_ide/src/syntax_highlighting/tags.rs
@@ -39,6 +39,7 @@ pub enum HighlightTag {
39 Union, 39 Union,
40 Local, 40 Local,
41 UnresolvedReference, 41 UnresolvedReference,
42 FormatSpecifier,
42} 43}
43 44
44#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] 45#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
@@ -81,6 +82,7 @@ impl HighlightTag {
81 HighlightTag::Union => "union", 82 HighlightTag::Union => "union",
82 HighlightTag::Local => "variable", 83 HighlightTag::Local => "variable",
83 HighlightTag::UnresolvedReference => "unresolved_reference", 84 HighlightTag::UnresolvedReference => "unresolved_reference",
85 HighlightTag::FormatSpecifier => "format_specifier",
84 } 86 }
85 } 87 }
86} 88}
diff --git a/crates/ra_prof/src/hprof.rs b/crates/ra_prof/src/hprof.rs
index 2b8a90363..a3f5321fb 100644
--- a/crates/ra_prof/src/hprof.rs
+++ b/crates/ra_prof/src/hprof.rs
@@ -30,8 +30,9 @@ pub fn init_from(spec: &str) {
30pub type Label = &'static str; 30pub type Label = &'static str;
31 31
32/// This function starts a profiling scope in the current execution stack with a given description. 32/// This function starts a profiling scope in the current execution stack with a given description.
33/// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop. 33/// It returns a `Profile` struct that measures elapsed time between this method invocation and `Profile` struct drop.
34/// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output. 34/// It supports nested profiling scopes in case when this function is invoked multiple times at the execution stack.
35/// In this case the profiling information will be nested at the output.
35/// Profiling information is being printed in the stderr. 36/// Profiling information is being printed in the stderr.
36/// 37///
37/// # Example 38/// # Example
@@ -58,36 +59,35 @@ pub type Label = &'static str;
58/// ``` 59/// ```
59pub fn profile(label: Label) -> Profiler { 60pub fn profile(label: Label) -> Profiler {
60 assert!(!label.is_empty()); 61 assert!(!label.is_empty());
61 let enabled = PROFILING_ENABLED.load(Ordering::Relaxed) 62
62 && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label)); 63 if PROFILING_ENABLED.load(Ordering::Relaxed)
63 let label = if enabled { Some(label) } else { None }; 64 && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label))
64 Profiler { label, detail: None } 65 {
66 Profiler(Some(ProfilerImpl { label, detail: None }))
67 } else {
68 Profiler(None)
69 }
65} 70}
66 71
67pub struct Profiler { 72pub struct Profiler(Option<ProfilerImpl>);
68 label: Option<Label>, 73
74struct ProfilerImpl {
75 label: Label,
69 detail: Option<String>, 76 detail: Option<String>,
70} 77}
71 78
72impl Profiler { 79impl Profiler {
73 pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler { 80 pub fn detail(mut self, detail: impl FnOnce() -> String) -> Profiler {
74 if self.label.is_some() { 81 if let Some(profiler) = &mut self.0 {
75 self.detail = Some(detail()) 82 profiler.detail = Some(detail())
76 } 83 }
77 self 84 self
78 } 85 }
79} 86}
80 87
81impl Drop for Profiler { 88impl Drop for ProfilerImpl {
82 fn drop(&mut self) { 89 fn drop(&mut self) {
83 match self { 90 PROFILE_STACK.with(|it| it.borrow_mut().pop(self.label, self.detail.take()));
84 Profiler { label: Some(label), detail } => {
85 PROFILE_STACK.with(|stack| {
86 stack.borrow_mut().pop(label, detail.take());
87 });
88 }
89 Profiler { label: None, .. } => (),
90 }
91 } 91 }
92} 92}
93 93
@@ -179,21 +179,18 @@ impl ProfileStack {
179 pub fn pop(&mut self, label: Label, detail: Option<String>) { 179 pub fn pop(&mut self, label: Label, detail: Option<String>) {
180 let start = self.starts.pop().unwrap(); 180 let start = self.starts.pop().unwrap();
181 let duration = start.elapsed(); 181 let duration = start.elapsed();
182 let level = self.starts.len();
183 self.messages.finish(Message { duration, label, detail }); 182 self.messages.finish(Message { duration, label, detail });
184 if level == 0 { 183 if self.starts.is_empty() {
185 let longer_than = self.filter.longer_than; 184 let longer_than = self.filter.longer_than;
186 // Convert to millis for comparison to avoid problems with rounding 185 // Convert to millis for comparison to avoid problems with rounding
187 // (otherwise we could print `0ms` despite user's `>0` filter when 186 // (otherwise we could print `0ms` despite user's `>0` filter when
188 // `duration` is just a few nanos). 187 // `duration` is just a few nanos).
189 if duration.as_millis() > longer_than.as_millis() { 188 if duration.as_millis() > longer_than.as_millis() {
190 let stderr = stderr();
191 if let Some(root) = self.messages.root() { 189 if let Some(root) = self.messages.root() {
192 print(&self.messages, root, 0, longer_than, &mut stderr.lock()); 190 print(&self.messages, root, 0, longer_than, &mut stderr().lock());
193 } 191 }
194 } 192 }
195 self.messages.clear(); 193 self.messages.clear();
196 assert!(self.starts.is_empty())
197 } 194 }
198 } 195 }
199} 196}
diff --git a/crates/ra_syntax/src/ast.rs b/crates/ra_syntax/src/ast.rs
index 7fca5661e..a716e525b 100644
--- a/crates/ra_syntax/src/ast.rs
+++ b/crates/ra_syntax/src/ast.rs
@@ -243,6 +243,21 @@ fn test_comments_preserve_trailing_whitespace() {
243} 243}
244 244
245#[test] 245#[test]
246fn test_four_slash_line_comment() {
247 let file = SourceFile::parse(
248 r#"
249 //// too many slashes to be a doc comment
250 /// doc comment
251 mod foo {}
252 "#,
253 )
254 .ok()
255 .unwrap();
256 let module = file.syntax().descendants().find_map(Module::cast).unwrap();
257 assert_eq!("doc comment", module.doc_comment_text().unwrap());
258}
259
260#[test]
246fn test_where_predicates() { 261fn test_where_predicates() {
247 fn assert_bound(text: &str, bound: Option<TypeBound>) { 262 fn assert_bound(text: &str, bound: Option<TypeBound>) {
248 assert_eq!(text, bound.unwrap().syntax().text().to_string()); 263 assert_eq!(text, bound.unwrap().syntax().text().to_string());
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index ee0f5cc40..492088353 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -22,8 +22,7 @@ pub fn path_unqualified(segment: ast::PathSegment) -> ast::Path {
22pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path { 22pub fn path_qualified(qual: ast::Path, segment: ast::PathSegment) -> ast::Path {
23 path_from_text(&format!("{}::{}", qual, segment)) 23 path_from_text(&format!("{}::{}", qual, segment))
24} 24}
25 25fn path_from_text(text: &str) -> ast::Path {
26pub fn path_from_text(text: &str) -> ast::Path {
27 ast_from_text(text) 26 ast_from_text(text)
28} 27}
29 28
diff --git a/crates/ra_syntax/src/ast/tokens.rs b/crates/ra_syntax/src/ast/tokens.rs
index 3865729b8..74906d8a6 100644
--- a/crates/ra_syntax/src/ast/tokens.rs
+++ b/crates/ra_syntax/src/ast/tokens.rs
@@ -13,7 +13,12 @@ impl Comment {
13 } 13 }
14 14
15 pub fn prefix(&self) -> &'static str { 15 pub fn prefix(&self) -> &'static str {
16 prefix_by_kind(self.kind()) 16 for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() {
17 if *k == self.kind() && self.text().starts_with(prefix) {
18 return prefix;
19 }
20 }
21 unreachable!()
17 } 22 }
18} 23}
19 24
@@ -48,6 +53,7 @@ pub enum CommentPlacement {
48const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = { 53const COMMENT_PREFIX_TO_KIND: &[(&str, CommentKind)] = {
49 use {CommentPlacement::*, CommentShape::*}; 54 use {CommentPlacement::*, CommentShape::*};
50 &[ 55 &[
56 ("////", CommentKind { shape: Line, doc: None }),
51 ("///", CommentKind { shape: Line, doc: Some(Outer) }), 57 ("///", CommentKind { shape: Line, doc: Some(Outer) }),
52 ("//!", CommentKind { shape: Line, doc: Some(Inner) }), 58 ("//!", CommentKind { shape: Line, doc: Some(Inner) }),
53 ("/**", CommentKind { shape: Block, doc: Some(Outer) }), 59 ("/**", CommentKind { shape: Block, doc: Some(Outer) }),
@@ -69,15 +75,6 @@ fn kind_by_prefix(text: &str) -> CommentKind {
69 panic!("bad comment text: {:?}", text) 75 panic!("bad comment text: {:?}", text)
70} 76}
71 77
72fn prefix_by_kind(kind: CommentKind) -> &'static str {
73 for (prefix, k) in COMMENT_PREFIX_TO_KIND.iter() {
74 if *k == kind {
75 return prefix;
76 }
77 }
78 unreachable!()
79}
80
81impl Whitespace { 78impl Whitespace {
82 pub fn spans_multiple_lines(&self) -> bool { 79 pub fn spans_multiple_lines(&self) -> bool {
83 let text = self.text(); 80 let text = self.text();
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index cee0248b6..514d6d1a9 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -20,7 +20,7 @@ globset = "0.4.4"
20itertools = "0.9.0" 20itertools = "0.9.0"
21jod-thread = "0.1.0" 21jod-thread = "0.1.0"
22log = "0.4.8" 22log = "0.4.8"
23lsp-types = { version = "0.73.0", features = ["proposed"] } 23lsp-types = { version = "0.74.0", features = ["proposed"] }
24parking_lot = "0.10.0" 24parking_lot = "0.10.0"
25pico-args = "0.3.1" 25pico-args = "0.3.1"
26rand = { version = "0.7.3", features = ["small_rng"] } 26rand = { version = "0.7.3", features = ["small_rng"] }
diff --git a/crates/rust-analyzer/src/conv.rs b/crates/rust-analyzer/src/conv.rs
index b0f911f71..7be5ebcdb 100644
--- a/crates/rust-analyzer/src/conv.rs
+++ b/crates/rust-analyzer/src/conv.rs
@@ -25,7 +25,8 @@ use crate::{
25 Result, 25 Result,
26}; 26};
27use semantic_tokens::{ 27use semantic_tokens::{
28 ATTRIBUTE, BUILTIN_TYPE, ENUM_MEMBER, LIFETIME, TYPE_ALIAS, UNION, UNRESOLVED_REFERENCE, 28 ATTRIBUTE, BUILTIN_TYPE, ENUM_MEMBER, FORMAT_SPECIFIER, LIFETIME, TYPE_ALIAS, UNION,
29 UNRESOLVED_REFERENCE,
29}; 30};
30 31
31pub trait Conv { 32pub trait Conv {
@@ -149,7 +150,7 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem {
149 detail: self.detail().map(|it| it.to_string()), 150 detail: self.detail().map(|it| it.to_string()),
150 filter_text: Some(self.lookup().to_string()), 151 filter_text: Some(self.lookup().to_string()),
151 kind: self.kind().map(|it| it.conv()), 152 kind: self.kind().map(|it| it.conv()),
152 text_edit: Some(text_edit), 153 text_edit: Some(text_edit.into()),
153 additional_text_edits: Some(additional_text_edits), 154 additional_text_edits: Some(additional_text_edits),
154 documentation: self.documentation().map(|it| it.conv()), 155 documentation: self.documentation().map(|it| it.conv()),
155 deprecated: Some(self.deprecated()), 156 deprecated: Some(self.deprecated()),
@@ -381,6 +382,7 @@ impl Conv for Highlight {
381 HighlightTag::Attribute => ATTRIBUTE, 382 HighlightTag::Attribute => ATTRIBUTE,
382 HighlightTag::Keyword => SemanticTokenType::KEYWORD, 383 HighlightTag::Keyword => SemanticTokenType::KEYWORD,
383 HighlightTag::UnresolvedReference => UNRESOLVED_REFERENCE, 384 HighlightTag::UnresolvedReference => UNRESOLVED_REFERENCE,
385 HighlightTag::FormatSpecifier => FORMAT_SPECIFIER,
384 }; 386 };
385 387
386 for modifier in self.modifiers.iter() { 388 for modifier in self.modifiers.iter() {
diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs
index 6caaf5f88..8db2dfa0c 100644
--- a/crates/rust-analyzer/src/main_loop/handlers.rs
+++ b/crates/rust-analyzer/src/main_loop/handlers.rs
@@ -326,10 +326,10 @@ pub fn handle_workspace_symbol(
326 326
327pub fn handle_goto_definition( 327pub fn handle_goto_definition(
328 world: WorldSnapshot, 328 world: WorldSnapshot,
329 params: req::TextDocumentPositionParams, 329 params: req::GotoDefinitionParams,
330) -> Result<Option<req::GotoDefinitionResponse>> { 330) -> Result<Option<req::GotoDefinitionResponse>> {
331 let _p = profile("handle_goto_definition"); 331 let _p = profile("handle_goto_definition");
332 let position = params.try_conv_with(&world)?; 332 let position = params.text_document_position_params.try_conv_with(&world)?;
333 let nav_info = match world.analysis().goto_definition(position)? { 333 let nav_info = match world.analysis().goto_definition(position)? {
334 None => return Ok(None), 334 None => return Ok(None),
335 Some(it) => it, 335 Some(it) => it,
@@ -340,10 +340,10 @@ pub fn handle_goto_definition(
340 340
341pub fn handle_goto_implementation( 341pub fn handle_goto_implementation(
342 world: WorldSnapshot, 342 world: WorldSnapshot,
343 params: req::TextDocumentPositionParams, 343 params: req::GotoImplementationParams,
344) -> Result<Option<req::GotoImplementationResponse>> { 344) -> Result<Option<req::GotoImplementationResponse>> {
345 let _p = profile("handle_goto_implementation"); 345 let _p = profile("handle_goto_implementation");
346 let position = params.try_conv_with(&world)?; 346 let position = params.text_document_position_params.try_conv_with(&world)?;
347 let nav_info = match world.analysis().goto_implementation(position)? { 347 let nav_info = match world.analysis().goto_implementation(position)? {
348 None => return Ok(None), 348 None => return Ok(None),
349 Some(it) => it, 349 Some(it) => it,
@@ -354,10 +354,10 @@ pub fn handle_goto_implementation(
354 354
355pub fn handle_goto_type_definition( 355pub fn handle_goto_type_definition(
356 world: WorldSnapshot, 356 world: WorldSnapshot,
357 params: req::TextDocumentPositionParams, 357 params: req::GotoTypeDefinitionParams,
358) -> Result<Option<req::GotoTypeDefinitionResponse>> { 358) -> Result<Option<req::GotoTypeDefinitionResponse>> {
359 let _p = profile("handle_goto_type_definition"); 359 let _p = profile("handle_goto_type_definition");
360 let position = params.try_conv_with(&world)?; 360 let position = params.text_document_position_params.try_conv_with(&world)?;
361 let nav_info = match world.analysis().goto_type_definition(position)? { 361 let nav_info = match world.analysis().goto_type_definition(position)? {
362 None => return Ok(None), 362 None => return Ok(None),
363 Some(it) => it, 363 Some(it) => it,
@@ -487,10 +487,10 @@ pub fn handle_folding_range(
487 487
488pub fn handle_signature_help( 488pub fn handle_signature_help(
489 world: WorldSnapshot, 489 world: WorldSnapshot,
490 params: req::TextDocumentPositionParams, 490 params: req::SignatureHelpParams,
491) -> Result<Option<req::SignatureHelp>> { 491) -> Result<Option<req::SignatureHelp>> {
492 let _p = profile("handle_signature_help"); 492 let _p = profile("handle_signature_help");
493 let position = params.try_conv_with(&world)?; 493 let position = params.text_document_position_params.try_conv_with(&world)?;
494 if let Some(call_info) = world.analysis().call_info(position)? { 494 if let Some(call_info) = world.analysis().call_info(position)? {
495 let concise = !world.config.call_info_full; 495 let concise = !world.config.call_info_full;
496 let mut active_parameter = call_info.active_parameter.map(|it| it as i64); 496 let mut active_parameter = call_info.active_parameter.map(|it| it as i64);
@@ -509,12 +509,9 @@ pub fn handle_signature_help(
509 } 509 }
510} 510}
511 511
512pub fn handle_hover( 512pub fn handle_hover(world: WorldSnapshot, params: req::HoverParams) -> Result<Option<Hover>> {
513 world: WorldSnapshot,
514 params: req::TextDocumentPositionParams,
515) -> Result<Option<Hover>> {
516 let _p = profile("handle_hover"); 513 let _p = profile("handle_hover");
517 let position = params.try_conv_with(&world)?; 514 let position = params.text_document_position_params.try_conv_with(&world)?;
518 let info = match world.analysis().hover(position)? { 515 let info = match world.analysis().hover(position)? {
519 None => return Ok(None), 516 None => return Ok(None),
520 Some(info) => info, 517 Some(info) => info,
@@ -878,8 +875,14 @@ pub fn handle_code_lens(
878 .map(|it| { 875 .map(|it| {
879 let range = it.node_range.conv_with(&line_index); 876 let range = it.node_range.conv_with(&line_index);
880 let pos = range.start; 877 let pos = range.start;
881 let lens_params = 878 let lens_params = req::GotoImplementationParams {
882 req::TextDocumentPositionParams::new(params.text_document.clone(), pos); 879 text_document_position_params: req::TextDocumentPositionParams::new(
880 params.text_document.clone(),
881 pos,
882 ),
883 work_done_progress_params: Default::default(),
884 partial_result_params: Default::default(),
885 };
883 CodeLens { 886 CodeLens {
884 range, 887 range,
885 command: None, 888 command: None,
@@ -894,7 +897,7 @@ pub fn handle_code_lens(
894#[derive(Debug, Serialize, Deserialize)] 897#[derive(Debug, Serialize, Deserialize)]
895#[serde(rename_all = "camelCase")] 898#[serde(rename_all = "camelCase")]
896enum CodeLensResolveData { 899enum CodeLensResolveData {
897 Impls(req::TextDocumentPositionParams), 900 Impls(req::GotoImplementationParams),
898} 901}
899 902
900pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> { 903pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Result<CodeLens> {
@@ -927,7 +930,7 @@ pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Re
927 title, 930 title,
928 command: "rust-analyzer.showReferences".into(), 931 command: "rust-analyzer.showReferences".into(),
929 arguments: Some(vec![ 932 arguments: Some(vec![
930 to_value(&lens_params.text_document.uri).unwrap(), 933 to_value(&lens_params.text_document_position_params.text_document.uri).unwrap(),
931 to_value(code_lens.range.start).unwrap(), 934 to_value(code_lens.range.start).unwrap(),
932 to_value(locations).unwrap(), 935 to_value(locations).unwrap(),
933 ]), 936 ]),
@@ -944,16 +947,16 @@ pub fn handle_code_lens_resolve(world: WorldSnapshot, code_lens: CodeLens) -> Re
944 947
945pub fn handle_document_highlight( 948pub fn handle_document_highlight(
946 world: WorldSnapshot, 949 world: WorldSnapshot,
947 params: req::TextDocumentPositionParams, 950 params: req::DocumentHighlightParams,
948) -> Result<Option<Vec<DocumentHighlight>>> { 951) -> Result<Option<Vec<DocumentHighlight>>> {
949 let _p = profile("handle_document_highlight"); 952 let _p = profile("handle_document_highlight");
950 let file_id = params.text_document.try_conv_with(&world)?; 953 let file_id = params.text_document_position_params.text_document.try_conv_with(&world)?;
951 let line_index = world.analysis().file_line_index(file_id)?; 954 let line_index = world.analysis().file_line_index(file_id)?;
952 955
953 let refs = match world 956 let refs = match world.analysis().find_all_refs(
954 .analysis() 957 params.text_document_position_params.try_conv_with(&world)?,
955 .find_all_refs(params.try_conv_with(&world)?, Some(SearchScope::single_file(file_id)))? 958 Some(SearchScope::single_file(file_id)),
956 { 959 )? {
957 None => return Ok(None), 960 None => return Ok(None),
958 Some(refs) => refs, 961 Some(refs) => refs,
959 }; 962 };
diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs
index ae3448892..0dae6bad4 100644
--- a/crates/rust-analyzer/src/req.rs
+++ b/crates/rust-analyzer/src/req.rs
@@ -8,14 +8,15 @@ pub use lsp_types::{
8 notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, 8 notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens,
9 CodeLensParams, CompletionParams, CompletionResponse, ConfigurationItem, ConfigurationParams, 9 CodeLensParams, CompletionParams, CompletionResponse, ConfigurationItem, ConfigurationParams,
10 DiagnosticTag, DidChangeConfigurationParams, DidChangeWatchedFilesParams, 10 DiagnosticTag, DidChangeConfigurationParams, DidChangeWatchedFilesParams,
11 DidChangeWatchedFilesRegistrationOptions, DocumentOnTypeFormattingParams, DocumentSymbolParams, 11 DidChangeWatchedFilesRegistrationOptions, DocumentHighlightParams,
12 DocumentSymbolResponse, FileSystemWatcher, Hover, InitializeResult, MessageType, 12 DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse,
13 PartialResultParams, ProgressParams, ProgressParamsValue, ProgressToken, 13 FileSystemWatcher, GotoDefinitionParams, GotoDefinitionResponse, Hover, HoverParams,
14 PublishDiagnosticsParams, ReferenceParams, Registration, RegistrationParams, SelectionRange, 14 InitializeResult, MessageType, PartialResultParams, ProgressParams, ProgressParamsValue,
15 SelectionRangeParams, SemanticTokensParams, SemanticTokensRangeParams, 15 ProgressToken, PublishDiagnosticsParams, ReferenceParams, Registration, RegistrationParams,
16 SelectionRange, SelectionRangeParams, SemanticTokensParams, SemanticTokensRangeParams,
16 SemanticTokensRangeResult, SemanticTokensResult, ServerCapabilities, ShowMessageParams, 17 SemanticTokensRangeResult, SemanticTokensResult, ServerCapabilities, ShowMessageParams,
17 SignatureHelp, SymbolKind, TextDocumentEdit, TextDocumentPositionParams, TextEdit, 18 SignatureHelp, SignatureHelpParams, SymbolKind, TextDocumentEdit, TextDocumentPositionParams,
18 WorkDoneProgressParams, WorkspaceEdit, WorkspaceSymbolParams, 19 TextEdit, WorkDoneProgressParams, WorkspaceEdit, WorkspaceSymbolParams,
19}; 20};
20use std::path::PathBuf; 21use std::path::PathBuf;
21 22
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index 10fe696f6..2dc5cb119 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -4,62 +4,69 @@ use std::ops;
4 4
5use lsp_types::{Range, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens}; 5use lsp_types::{Range, SemanticToken, SemanticTokenModifier, SemanticTokenType, SemanticTokens};
6 6
7pub(crate) const ATTRIBUTE: SemanticTokenType = SemanticTokenType::new("attribute"); 7macro_rules! define_semantic_token_types {
8pub(crate) const BUILTIN_TYPE: SemanticTokenType = SemanticTokenType::new("builtinType"); 8 ($(($ident:ident, $string:literal)),*$(,)?) => {
9pub(crate) const ENUM_MEMBER: SemanticTokenType = SemanticTokenType::new("enumMember"); 9 $(pub(crate) const $ident: SemanticTokenType = SemanticTokenType::new($string);)*
10pub(crate) const LIFETIME: SemanticTokenType = SemanticTokenType::new("lifetime"); 10
11pub(crate) const TYPE_ALIAS: SemanticTokenType = SemanticTokenType::new("typeAlias"); 11 pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[
12pub(crate) const UNION: SemanticTokenType = SemanticTokenType::new("union"); 12 SemanticTokenType::COMMENT,
13pub(crate) const UNRESOLVED_REFERENCE: SemanticTokenType = 13 SemanticTokenType::KEYWORD,
14 SemanticTokenType::new("unresolvedReference"); 14 SemanticTokenType::STRING,
15 15 SemanticTokenType::NUMBER,
16pub(crate) const CONSTANT: SemanticTokenModifier = SemanticTokenModifier::new("constant"); 16 SemanticTokenType::REGEXP,
17pub(crate) const CONTROL_FLOW: SemanticTokenModifier = SemanticTokenModifier::new("controlFlow"); 17 SemanticTokenType::OPERATOR,
18pub(crate) const MUTABLE: SemanticTokenModifier = SemanticTokenModifier::new("mutable"); 18 SemanticTokenType::NAMESPACE,
19pub(crate) const UNSAFE: SemanticTokenModifier = SemanticTokenModifier::new("unsafe"); 19 SemanticTokenType::TYPE,
20 20 SemanticTokenType::STRUCT,
21pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[ 21 SemanticTokenType::CLASS,
22 SemanticTokenType::COMMENT, 22 SemanticTokenType::INTERFACE,
23 SemanticTokenType::KEYWORD, 23 SemanticTokenType::ENUM,
24 SemanticTokenType::STRING, 24 SemanticTokenType::TYPE_PARAMETER,
25 SemanticTokenType::NUMBER, 25 SemanticTokenType::FUNCTION,
26 SemanticTokenType::REGEXP, 26 SemanticTokenType::MEMBER,
27 SemanticTokenType::OPERATOR, 27 SemanticTokenType::PROPERTY,
28 SemanticTokenType::NAMESPACE, 28 SemanticTokenType::MACRO,
29 SemanticTokenType::TYPE, 29 SemanticTokenType::VARIABLE,
30 SemanticTokenType::STRUCT, 30 SemanticTokenType::PARAMETER,
31 SemanticTokenType::CLASS, 31 SemanticTokenType::LABEL,
32 SemanticTokenType::INTERFACE, 32 $($ident),*
33 SemanticTokenType::ENUM, 33 ];
34 SemanticTokenType::TYPE_PARAMETER, 34 };
35 SemanticTokenType::FUNCTION, 35}
36 SemanticTokenType::MEMBER, 36
37 SemanticTokenType::PROPERTY, 37define_semantic_token_types![
38 SemanticTokenType::MACRO, 38 (ATTRIBUTE, "attribute"),
39 SemanticTokenType::VARIABLE, 39 (BUILTIN_TYPE, "builtinType"),
40 SemanticTokenType::PARAMETER, 40 (ENUM_MEMBER, "enumMember"),
41 SemanticTokenType::LABEL, 41 (LIFETIME, "lifetime"),
42 ATTRIBUTE, 42 (TYPE_ALIAS, "typeAlias"),
43 BUILTIN_TYPE, 43 (UNION, "union"),
44 ENUM_MEMBER, 44 (UNRESOLVED_REFERENCE, "unresolvedReference"),
45 LIFETIME, 45 (FORMAT_SPECIFIER, "formatSpecifier"),
46 TYPE_ALIAS,
47 UNION,
48 UNRESOLVED_REFERENCE,
49]; 46];
50 47
51pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[ 48macro_rules! define_semantic_token_modifiers {
52 SemanticTokenModifier::DOCUMENTATION, 49 ($(($ident:ident, $string:literal)),*$(,)?) => {
53 SemanticTokenModifier::DECLARATION, 50 $(pub(crate) const $ident: SemanticTokenModifier = SemanticTokenModifier::new($string);)*
54 SemanticTokenModifier::DEFINITION, 51
55 SemanticTokenModifier::STATIC, 52 pub(crate) const SUPPORTED_MODIFIERS: &[SemanticTokenModifier] = &[
56 SemanticTokenModifier::ABSTRACT, 53 SemanticTokenModifier::DOCUMENTATION,
57 SemanticTokenModifier::DEPRECATED, 54 SemanticTokenModifier::DECLARATION,
58 SemanticTokenModifier::READONLY, 55 SemanticTokenModifier::DEFINITION,
59 CONSTANT, 56 SemanticTokenModifier::STATIC,
60 MUTABLE, 57 SemanticTokenModifier::ABSTRACT,
61 UNSAFE, 58 SemanticTokenModifier::DEPRECATED,
62 CONTROL_FLOW, 59 SemanticTokenModifier::READONLY,
60 $($ident),*
61 ];
62 };
63}
64
65define_semantic_token_modifiers![
66 (CONSTANT, "constant"),
67 (CONTROL_FLOW, "controlFlow"),
68 (MUTABLE, "mutable"),
69 (UNSAFE, "unsafe"),
63]; 70];
64 71
65#[derive(Default)] 72#[derive(Default)]
diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs
index f6245ddd4..07b8114c6 100644
--- a/crates/rust-analyzer/tests/heavy_tests/main.rs
+++ b/crates/rust-analyzer/tests/heavy_tests/main.rs
@@ -4,8 +4,8 @@ use std::{collections::HashMap, path::PathBuf, time::Instant};
4 4
5use lsp_types::{ 5use lsp_types::{
6 CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions, 6 CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions,
7 PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams, 7 GotoDefinitionParams, HoverParams, PartialResultParams, Position, Range, TextDocumentItem,
8 WorkDoneProgressParams, 8 TextDocumentPositionParams, WorkDoneProgressParams,
9}; 9};
10use rust_analyzer::req::{ 10use rust_analyzer::req::{
11 CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument, 11 CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument,
@@ -610,10 +610,14 @@ fn main() { message(); }
610 }) 610 })
611 .server(); 611 .server();
612 server.wait_until_workspace_is_loaded(); 612 server.wait_until_workspace_is_loaded();
613 let res = server.send_request::<GotoDefinition>(TextDocumentPositionParams::new( 613 let res = server.send_request::<GotoDefinition>(GotoDefinitionParams {
614 server.doc_id("src/main.rs"), 614 text_document_position_params: TextDocumentPositionParams::new(
615 Position::new(2, 15), 615 server.doc_id("src/main.rs"),
616 )); 616 Position::new(2, 15),
617 ),
618 work_done_progress_params: Default::default(),
619 partial_result_params: Default::default(),
620 });
617 assert!(format!("{}", res).contains("hello.rs")); 621 assert!(format!("{}", res).contains("hello.rs"));
618} 622}
619 623
@@ -692,10 +696,13 @@ pub fn foo(_input: TokenStream) -> TokenStream {
692 .root("bar") 696 .root("bar")
693 .server(); 697 .server();
694 server.wait_until_workspace_is_loaded(); 698 server.wait_until_workspace_is_loaded();
695 let res = server.send_request::<HoverRequest>(TextDocumentPositionParams::new( 699 let res = server.send_request::<HoverRequest>(HoverParams {
696 server.doc_id("foo/src/main.rs"), 700 text_document_position_params: TextDocumentPositionParams::new(
697 Position::new(7, 9), 701 server.doc_id("foo/src/main.rs"),
698 )); 702 Position::new(7, 9),
703 ),
704 work_done_progress_params: Default::default(),
705 });
699 706
700 let value = res.get("contents").unwrap().get("value").unwrap().to_string(); 707 let value = res.get("contents").unwrap().get("value").unwrap().to_string();
701 assert_eq!(value, r#""```rust\nfoo::Bar\nfn bar()\n```""#) 708 assert_eq!(value, r#""```rust\nfoo::Bar\nfn bar()\n```""#)