Merge branch 'master' into compute-lazy-assits
# Conflicts: # crates/rust-analyzer/src/main_loop/handlers.rs # crates/rust-analyzer/src/to_proto.rs
This commit is contained in:
commit
6a0083a519
50 changed files with 1191 additions and 1829 deletions
|
|
@ -125,3 +125,81 @@ pub(crate) fn completions(
|
|||
|
||||
Some(acc)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::completion::completion_config::CompletionConfig;
|
||||
use crate::mock_analysis::analysis_and_position;
|
||||
|
||||
struct DetailAndDocumentation<'a> {
|
||||
detail: &'a str,
|
||||
documentation: &'a str,
|
||||
}
|
||||
|
||||
fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) {
|
||||
let (analysis, position) = analysis_and_position(fixture);
|
||||
let config = CompletionConfig::default();
|
||||
let completions = analysis.completions(&config, position).unwrap().unwrap();
|
||||
for item in completions {
|
||||
if item.detail() == Some(expected.detail) {
|
||||
let opt = item.documentation();
|
||||
let doc = opt.as_ref().map(|it| it.as_str());
|
||||
assert_eq!(doc, Some(expected.documentation));
|
||||
return;
|
||||
}
|
||||
}
|
||||
panic!("completion detail not found: {}", expected.detail)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
|
||||
check_detail_and_documentation(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
macro_rules! bar {
|
||||
() => {
|
||||
struct Bar;
|
||||
impl Bar {
|
||||
#[doc = "Do the foo"]
|
||||
fn foo(&self) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bar!();
|
||||
|
||||
fn foo() {
|
||||
let bar = Bar;
|
||||
bar.fo<|>;
|
||||
}
|
||||
"#,
|
||||
DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" },
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() {
|
||||
check_detail_and_documentation(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
macro_rules! bar {
|
||||
() => {
|
||||
struct Bar;
|
||||
impl Bar {
|
||||
/// Do the foo
|
||||
fn foo(&self) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bar!();
|
||||
|
||||
fn foo() {
|
||||
let bar = Bar;
|
||||
bar.fo<|>;
|
||||
}
|
||||
"#,
|
||||
DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use std::{
|
|||
use hir::{Docs, Documentation, HasSource, HirDisplay};
|
||||
use ra_ide_db::RootDatabase;
|
||||
use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
|
||||
use stdx::SepBy;
|
||||
use stdx::{split1, SepBy};
|
||||
|
||||
use crate::display::{generic_parameters, where_predicates};
|
||||
|
||||
|
|
@ -207,7 +207,16 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
|
|||
res.push(raw_param);
|
||||
}
|
||||
|
||||
res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
|
||||
// macro-generated functions are missing whitespace
|
||||
fn fmt_param(param: ast::Param) -> String {
|
||||
let text = param.syntax().text().to_string();
|
||||
match split1(&text, ':') {
|
||||
Some((left, right)) => format!("{}: {}", left.trim(), right.trim()),
|
||||
_ => text,
|
||||
}
|
||||
}
|
||||
|
||||
res.extend(param_list.params().map(fmt_param));
|
||||
res_types.extend(param_list.params().map(|param| {
|
||||
let param_text = param.syntax().text().to_string();
|
||||
match param_text.split(':').nth(1).and_then(|it| it.get(1..)) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use std::iter::once;
|
||||
|
||||
use hir::{
|
||||
Adt, AsAssocItem, AssocItemContainer, FieldSource, HasSource, HirDisplay, ModuleDef,
|
||||
ModuleSource, Semantics,
|
||||
Adt, AsAssocItem, AssocItemContainer, Documentation, FieldSource, HasSource, HirDisplay,
|
||||
ModuleDef, ModuleSource, Semantics,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use ra_db::SourceDatabase;
|
||||
|
|
@ -10,12 +10,7 @@ use ra_ide_db::{
|
|||
defs::{classify_name, classify_name_ref, Definition},
|
||||
RootDatabase,
|
||||
};
|
||||
use ra_syntax::{
|
||||
ast::{self, DocCommentsOwner},
|
||||
match_ast, AstNode,
|
||||
SyntaxKind::*,
|
||||
SyntaxToken, TokenAtOffset,
|
||||
};
|
||||
use ra_syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
|
||||
|
||||
use crate::{
|
||||
display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel},
|
||||
|
|
@ -169,13 +164,15 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
|
|||
return match def {
|
||||
Definition::Macro(it) => {
|
||||
let src = it.source(db);
|
||||
hover_text(src.value.doc_comment_text(), Some(macro_label(&src.value)), mod_path)
|
||||
let docs = Documentation::from_ast(&src.value).map(Into::into);
|
||||
hover_text(docs, Some(macro_label(&src.value)), mod_path)
|
||||
}
|
||||
Definition::Field(it) => {
|
||||
let src = it.source(db);
|
||||
match src.value {
|
||||
FieldSource::Named(it) => {
|
||||
hover_text(it.doc_comment_text(), it.short_label(), mod_path)
|
||||
let docs = Documentation::from_ast(&it).map(Into::into);
|
||||
hover_text(docs, it.short_label(), mod_path)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
|
|
@ -183,7 +180,8 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
|
|||
Definition::ModuleDef(it) => match it {
|
||||
ModuleDef::Module(it) => match it.definition_source(db).value {
|
||||
ModuleSource::Module(it) => {
|
||||
hover_text(it.doc_comment_text(), it.short_label(), mod_path)
|
||||
let docs = Documentation::from_ast(&it).map(Into::into);
|
||||
hover_text(docs, it.short_label(), mod_path)
|
||||
}
|
||||
_ => None,
|
||||
},
|
||||
|
|
@ -208,10 +206,11 @@ fn hover_text_from_name_kind(db: &RootDatabase, def: Definition) -> Option<Strin
|
|||
fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<String>
|
||||
where
|
||||
D: HasSource<Ast = A>,
|
||||
A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel,
|
||||
A: ast::DocCommentsOwner + ast::NameOwner + ShortLabel + ast::AttrsOwner,
|
||||
{
|
||||
let src = def.source(db);
|
||||
hover_text(src.value.doc_comment_text(), src.value.short_label(), mod_path)
|
||||
let docs = Documentation::from_ast(&src.value).map(Into::into);
|
||||
hover_text(docs, src.value.short_label(), mod_path)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -951,4 +950,106 @@ fn func(foo: i32) { if true { <|>foo; }; }
|
|||
&["mod my"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hover_struct_doc_comment() {
|
||||
check_hover_result(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
/// bar docs
|
||||
struct Bar;
|
||||
|
||||
fn foo() {
|
||||
let bar = Ba<|>r;
|
||||
}
|
||||
"#,
|
||||
&["struct Bar\n```\n___\n\nbar docs"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hover_struct_doc_attr() {
|
||||
check_hover_result(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
#[doc = "bar docs"]
|
||||
struct Bar;
|
||||
|
||||
fn foo() {
|
||||
let bar = Ba<|>r;
|
||||
}
|
||||
"#,
|
||||
&["struct Bar\n```\n___\n\nbar docs"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hover_struct_doc_attr_multiple_and_mixed() {
|
||||
check_hover_result(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
/// bar docs 0
|
||||
#[doc = "bar docs 1"]
|
||||
#[doc = "bar docs 2"]
|
||||
struct Bar;
|
||||
|
||||
fn foo() {
|
||||
let bar = Ba<|>r;
|
||||
}
|
||||
"#,
|
||||
&["struct Bar\n```\n___\n\nbar docs 0\n\nbar docs 1\n\nbar docs 2"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hover_macro_generated_struct_fn_doc_comment() {
|
||||
check_hover_result(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
macro_rules! bar {
|
||||
() => {
|
||||
struct Bar;
|
||||
impl Bar {
|
||||
/// Do the foo
|
||||
fn foo(&self) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bar!();
|
||||
|
||||
fn foo() {
|
||||
let bar = Bar;
|
||||
bar.fo<|>o();
|
||||
}
|
||||
"#,
|
||||
&["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\n Do the foo"],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hover_macro_generated_struct_fn_doc_attr() {
|
||||
check_hover_result(
|
||||
r#"
|
||||
//- /lib.rs
|
||||
macro_rules! bar {
|
||||
() => {
|
||||
struct Bar;
|
||||
impl Bar {
|
||||
#[doc = "Do the foo"]
|
||||
fn foo(&self) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bar!();
|
||||
|
||||
fn foo() {
|
||||
let bar = Bar;
|
||||
bar.fo<|>o();
|
||||
}
|
||||
"#,
|
||||
&["Bar\n```\n\n```rust\nfn foo(&self)\n```\n___\n\nDo the foo"],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.string_literal { color: #CC9393; }
|
||||
.field { color: #94BFF3; }
|
||||
.function { color: #93E0E3; }
|
||||
.operator.unsafe { color: #E28C14; }
|
||||
.parameter { color: #94BFF3; }
|
||||
.text { color: #DCDCCC; }
|
||||
.type { color: #7CB8BB; }
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.string_literal { color: #CC9393; }
|
||||
.field { color: #94BFF3; }
|
||||
.function { color: #93E0E3; }
|
||||
.operator.unsafe { color: #E28C14; }
|
||||
.parameter { color: #94BFF3; }
|
||||
.text { color: #DCDCCC; }
|
||||
.type { color: #7CB8BB; }
|
||||
|
|
|
|||
48
crates/ra_ide/src/snapshots/highlight_unsafe.html
Normal file
48
crates/ra_ide/src/snapshots/highlight_unsafe.html
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
|
||||
<style>
|
||||
body { margin: 0; }
|
||||
pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padding: 0.4em; }
|
||||
|
||||
.lifetime { color: #DFAF8F; font-style: italic; }
|
||||
.comment { color: #7F9F7F; }
|
||||
.struct, .enum { color: #7CB8BB; }
|
||||
.enum_variant { color: #BDE0F3; }
|
||||
.string_literal { color: #CC9393; }
|
||||
.field { color: #94BFF3; }
|
||||
.function { color: #93E0E3; }
|
||||
.operator.unsafe { color: #E28C14; }
|
||||
.parameter { color: #94BFF3; }
|
||||
.text { color: #DCDCCC; }
|
||||
.type { color: #7CB8BB; }
|
||||
.builtin_type { color: #8CD0D3; }
|
||||
.type_param { color: #DFAF8F; }
|
||||
.attribute { color: #94BFF3; }
|
||||
.numeric_literal { color: #BFEBBF; }
|
||||
.bool_literal { color: #BFE6EB; }
|
||||
.macro { color: #94BFF3; }
|
||||
.module { color: #AFD8AF; }
|
||||
.variable { color: #DCDCCC; }
|
||||
.format_specifier { color: #CC696B; }
|
||||
.mutable { text-decoration: underline; }
|
||||
|
||||
.keyword { color: #F0DFAF; font-weight: bold; }
|
||||
.keyword.unsafe { color: #BC8383; font-weight: bold; }
|
||||
.control { font-style: italic; }
|
||||
</style>
|
||||
<pre><code><span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span>() {}
|
||||
|
||||
<span class="keyword">struct</span> <span class="struct declaration">HasUnsafeFn</span>;
|
||||
|
||||
<span class="keyword">impl</span> <span class="struct">HasUnsafeFn</span> {
|
||||
<span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_method</span>(&<span class="self_keyword">self</span>) {}
|
||||
}
|
||||
|
||||
<span class="keyword">fn</span> <span class="function declaration">main</span>() {
|
||||
<span class="keyword">let</span> <span class="variable declaration">x</span> = &<span class="numeric_literal">5</span> <span class="keyword">as</span> *<span class="keyword">const</span> <span class="builtin_type">usize</span>;
|
||||
<span class="keyword unsafe">unsafe</span> {
|
||||
<span class="function unsafe">unsafe_fn</span>();
|
||||
<span class="struct">HasUnsafeFn</span>.<span class="function unsafe">unsafe_method</span>();
|
||||
<span class="keyword">let</span> <span class="variable declaration">y</span> = <span class="operator unsafe">*</span><span class="variable">x</span>;
|
||||
<span class="keyword">let</span> <span class="variable declaration">z</span> = -<span class="variable">x</span>;
|
||||
}
|
||||
}</code></pre>
|
||||
|
|
@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.string_literal { color: #CC9393; }
|
||||
.field { color: #94BFF3; }
|
||||
.function { color: #93E0E3; }
|
||||
.operator.unsafe { color: #E28C14; }
|
||||
.parameter { color: #94BFF3; }
|
||||
.text { color: #DCDCCC; }
|
||||
.type { color: #7CB8BB; }
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.string_literal { color: #CC9393; }
|
||||
.field { color: #94BFF3; }
|
||||
.function { color: #93E0E3; }
|
||||
.operator.unsafe { color: #E28C14; }
|
||||
.parameter { color: #94BFF3; }
|
||||
.text { color: #DCDCCC; }
|
||||
.type { color: #7CB8BB; }
|
||||
|
|
|
|||
|
|
@ -406,6 +406,23 @@ fn highlight_element(
|
|||
_ => h,
|
||||
}
|
||||
}
|
||||
PREFIX_EXPR => {
|
||||
let prefix_expr = element.into_node().and_then(ast::PrefixExpr::cast)?;
|
||||
match prefix_expr.op_kind() {
|
||||
Some(ast::PrefixOp::Deref) => {}
|
||||
_ => return None,
|
||||
}
|
||||
|
||||
let expr = prefix_expr.expr()?;
|
||||
let ty = sema.type_of_expr(&expr)?;
|
||||
if !ty.is_raw_ptr() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut h = Highlight::new(HighlightTag::Operator);
|
||||
h |= HighlightModifier::Unsafe;
|
||||
h
|
||||
}
|
||||
|
||||
k if k.is_keyword() => {
|
||||
let h = Highlight::new(HighlightTag::Keyword);
|
||||
|
|
@ -458,7 +475,13 @@ fn highlight_name(db: &RootDatabase, def: Definition) -> Highlight {
|
|||
Definition::Field(_) => HighlightTag::Field,
|
||||
Definition::ModuleDef(def) => match def {
|
||||
hir::ModuleDef::Module(_) => HighlightTag::Module,
|
||||
hir::ModuleDef::Function(_) => HighlightTag::Function,
|
||||
hir::ModuleDef::Function(func) => {
|
||||
let mut h = HighlightTag::Function.into();
|
||||
if func.is_unsafe(db) {
|
||||
h |= HighlightModifier::Unsafe;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HighlightTag::Struct,
|
||||
hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HighlightTag::Enum,
|
||||
hir::ModuleDef::Adt(hir::Adt::Union(_)) => HighlightTag::Union,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.string_literal { color: #CC9393; }
|
||||
.field { color: #94BFF3; }
|
||||
.function { color: #93E0E3; }
|
||||
.operator.unsafe { color: #E28C14; }
|
||||
.parameter { color: #94BFF3; }
|
||||
.text { color: #DCDCCC; }
|
||||
.type { color: #7CB8BB; }
|
||||
|
|
|
|||
|
|
@ -24,12 +24,14 @@ pub enum HighlightTag {
|
|||
Enum,
|
||||
EnumVariant,
|
||||
Field,
|
||||
FormatSpecifier,
|
||||
Function,
|
||||
Keyword,
|
||||
Lifetime,
|
||||
Macro,
|
||||
Module,
|
||||
NumericLiteral,
|
||||
Operator,
|
||||
SelfKeyword,
|
||||
SelfType,
|
||||
Static,
|
||||
|
|
@ -41,8 +43,6 @@ pub enum HighlightTag {
|
|||
Union,
|
||||
Local,
|
||||
UnresolvedReference,
|
||||
FormatSpecifier,
|
||||
Operator,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
|
|
@ -72,12 +72,14 @@ impl HighlightTag {
|
|||
HighlightTag::Enum => "enum",
|
||||
HighlightTag::EnumVariant => "enum_variant",
|
||||
HighlightTag::Field => "field",
|
||||
HighlightTag::FormatSpecifier => "format_specifier",
|
||||
HighlightTag::Function => "function",
|
||||
HighlightTag::Keyword => "keyword",
|
||||
HighlightTag::Lifetime => "lifetime",
|
||||
HighlightTag::Macro => "macro",
|
||||
HighlightTag::Module => "module",
|
||||
HighlightTag::NumericLiteral => "numeric_literal",
|
||||
HighlightTag::Operator => "operator",
|
||||
HighlightTag::SelfKeyword => "self_keyword",
|
||||
HighlightTag::SelfType => "self_type",
|
||||
HighlightTag::Static => "static",
|
||||
|
|
@ -89,8 +91,6 @@ impl HighlightTag {
|
|||
HighlightTag::Union => "union",
|
||||
HighlightTag::Local => "variable",
|
||||
HighlightTag::UnresolvedReference => "unresolved_reference",
|
||||
HighlightTag::FormatSpecifier => "format_specifier",
|
||||
HighlightTag::Operator => "operator",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -258,3 +258,34 @@ fn main() {
|
|||
fs::write(dst_file, &actual_html).unwrap();
|
||||
assert_eq_text!(expected_html, actual_html);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unsafe_highlighting() {
|
||||
let (analysis, file_id) = single_file(
|
||||
r#"
|
||||
unsafe fn unsafe_fn() {}
|
||||
|
||||
struct HasUnsafeFn;
|
||||
|
||||
impl HasUnsafeFn {
|
||||
unsafe fn unsafe_method(&self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = &5 as *const usize;
|
||||
unsafe {
|
||||
unsafe_fn();
|
||||
HasUnsafeFn.unsafe_method();
|
||||
let y = *x;
|
||||
let z = -x;
|
||||
}
|
||||
}
|
||||
"#
|
||||
.trim(),
|
||||
);
|
||||
let dst_file = project_dir().join("crates/ra_ide/src/snapshots/highlight_unsafe.html");
|
||||
let actual_html = &analysis.highlight_as_html(file_id, false).unwrap();
|
||||
let expected_html = &read_text(&dst_file);
|
||||
fs::write(dst_file, &actual_html).unwrap();
|
||||
assert_eq_text!(expected_html, actual_html);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue