Skip to content

Commit 6a0083a

Browse files
committed
Merge branch 'master' into compute-lazy-assits
# Conflicts: # crates/rust-analyzer/src/main_loop/handlers.rs # crates/rust-analyzer/src/to_proto.rs
2 parents 1f7de30 + 794f6da commit 6a0083a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1191
-1829
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ crates/*/target
88
*.iml
99
.vscode/settings.json
1010
*.html
11+
generated_assists.adoc
12+
generated_features.adoc

Cargo.lock

+15-14
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ra_hir/src/code_model.rs

+8
Original file line numberDiff line numberDiff line change
@@ -637,6 +637,10 @@ impl Function {
637637
db.function_data(self.id).params.clone()
638638
}
639639

640+
pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
641+
db.function_data(self.id).is_unsafe
642+
}
643+
640644
pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
641645
let _p = profile("Function::diagnostics");
642646
let infer = db.infer(self.id.into());
@@ -1190,6 +1194,10 @@ impl Type {
11901194
)
11911195
}
11921196

1197+
pub fn is_raw_ptr(&self) -> bool {
1198+
matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. }))
1199+
}
1200+
11931201
pub fn contains_unknown(&self) -> bool {
11941202
return go(&self.ty.value);
11951203

crates/ra_hir_def/src/attr.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,18 @@ impl Attrs {
8787
}
8888

8989
pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs {
90+
let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map(
91+
|docs_text| Attr {
92+
input: Some(AttrInput::Literal(SmolStr::new(docs_text))),
93+
path: ModPath::from(hir_expand::name!(doc)),
94+
},
95+
);
9096
let mut attrs = owner.attrs().peekable();
9197
let entries = if attrs.peek().is_none() {
9298
// Avoid heap allocation
9399
None
94100
} else {
95-
Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect())
101+
Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect())
96102
};
97103
Attrs { entries }
98104
}

crates/ra_hir_def/src/data.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub struct FunctionData {
3434
/// True if the first param is `self`. This is relevant to decide whether this
3535
/// can be called as a method.
3636
pub has_self_param: bool,
37+
pub is_unsafe: bool,
3738
pub visibility: RawVisibility,
3839
}
3940

@@ -85,11 +86,14 @@ impl FunctionData {
8586
ret_type
8687
};
8788

89+
let is_unsafe = src.value.unsafe_token().is_some();
90+
8891
let vis_default = RawVisibility::default_for_container(loc.container);
8992
let visibility =
9093
RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility()));
9194

92-
let sig = FunctionData { name, params, ret_type, has_self_param, visibility, attrs };
95+
let sig =
96+
FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs };
9397
Arc::new(sig)
9498
}
9599
}

crates/ra_hir_def/src/docs.rs

+48-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,13 @@ impl Documentation {
2929
Documentation(s.into())
3030
}
3131

32+
pub fn from_ast<N>(node: &N) -> Option<Documentation>
33+
where
34+
N: ast::DocCommentsOwner + ast::AttrsOwner,
35+
{
36+
docs_from_ast(node)
37+
}
38+
3239
pub fn as_str(&self) -> &str {
3340
&*self.0
3441
}
@@ -70,6 +77,45 @@ impl Documentation {
7077
}
7178
}
7279

73-
pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> {
74-
node.doc_comment_text().map(|it| Documentation::new(&it))
80+
pub(crate) fn docs_from_ast<N>(node: &N) -> Option<Documentation>
81+
where
82+
N: ast::DocCommentsOwner + ast::AttrsOwner,
83+
{
84+
let doc_comment_text = node.doc_comment_text();
85+
let doc_attr_text = expand_doc_attrs(node);
86+
let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text);
87+
docs.map(|it| Documentation::new(&it))
88+
}
89+
90+
fn merge_doc_comments_and_attrs(
91+
doc_comment_text: Option<String>,
92+
doc_attr_text: Option<String>,
93+
) -> Option<String> {
94+
match (doc_comment_text, doc_attr_text) {
95+
(Some(mut comment_text), Some(attr_text)) => {
96+
comment_text.push_str("\n\n");
97+
comment_text.push_str(&attr_text);
98+
Some(comment_text)
99+
}
100+
(Some(comment_text), None) => Some(comment_text),
101+
(None, Some(attr_text)) => Some(attr_text),
102+
(None, None) => None,
103+
}
104+
}
105+
106+
fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> {
107+
let mut docs = String::new();
108+
for attr in owner.attrs() {
109+
if let Some(("doc", value)) =
110+
attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str()))
111+
{
112+
docs.push_str(value);
113+
docs.push_str("\n\n");
114+
}
115+
}
116+
if docs.is_empty() {
117+
None
118+
} else {
119+
Some(docs.trim_end_matches("\n\n").to_owned())
120+
}
75121
}

crates/ra_hir_expand/src/name.rs

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ pub mod known {
153153
str,
154154
// Special names
155155
macro_rules,
156+
doc,
156157
// Components of known path (value or mod name)
157158
std,
158159
core,

crates/ra_ide/src/completion.rs

+78
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,81 @@ pub(crate) fn completions(
125125

126126
Some(acc)
127127
}
128+
129+
#[cfg(test)]
130+
mod tests {
131+
use crate::completion::completion_config::CompletionConfig;
132+
use crate::mock_analysis::analysis_and_position;
133+
134+
struct DetailAndDocumentation<'a> {
135+
detail: &'a str,
136+
documentation: &'a str,
137+
}
138+
139+
fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) {
140+
let (analysis, position) = analysis_and_position(fixture);
141+
let config = CompletionConfig::default();
142+
let completions = analysis.completions(&config, position).unwrap().unwrap();
143+
for item in completions {
144+
if item.detail() == Some(expected.detail) {
145+
let opt = item.documentation();
146+
let doc = opt.as_ref().map(|it| it.as_str());
147+
assert_eq!(doc, Some(expected.documentation));
148+
return;
149+
}
150+
}
151+
panic!("completion detail not found: {}", expected.detail)
152+
}
153+
154+
#[test]
155+
fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() {
156+
check_detail_and_documentation(
157+
r#"
158+
//- /lib.rs
159+
macro_rules! bar {
160+
() => {
161+
struct Bar;
162+
impl Bar {
163+
#[doc = "Do the foo"]
164+
fn foo(&self) {}
165+
}
166+
}
167+
}
168+
169+
bar!();
170+
171+
fn foo() {
172+
let bar = Bar;
173+
bar.fo<|>;
174+
}
175+
"#,
176+
DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" },
177+
);
178+
}
179+
180+
#[test]
181+
fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() {
182+
check_detail_and_documentation(
183+
r#"
184+
//- /lib.rs
185+
macro_rules! bar {
186+
() => {
187+
struct Bar;
188+
impl Bar {
189+
/// Do the foo
190+
fn foo(&self) {}
191+
}
192+
}
193+
}
194+
195+
bar!();
196+
197+
fn foo() {
198+
let bar = Bar;
199+
bar.fo<|>;
200+
}
201+
"#,
202+
DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" },
203+
);
204+
}
205+
}

crates/ra_ide/src/display/function_signature.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::{
1010
use hir::{Docs, Documentation, HasSource, HirDisplay};
1111
use ra_ide_db::RootDatabase;
1212
use ra_syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
13-
use stdx::SepBy;
13+
use stdx::{split1, SepBy};
1414

1515
use crate::display::{generic_parameters, where_predicates};
1616

@@ -207,7 +207,16 @@ impl From<&'_ ast::FnDef> for FunctionSignature {
207207
res.push(raw_param);
208208
}
209209

210-
res.extend(param_list.params().map(|param| param.syntax().text().to_string()));
210+
// macro-generated functions are missing whitespace
211+
fn fmt_param(param: ast::Param) -> String {
212+
let text = param.syntax().text().to_string();
213+
match split1(&text, ':') {
214+
Some((left, right)) => format!("{}: {}", left.trim(), right.trim()),
215+
_ => text,
216+
}
217+
}
218+
219+
res.extend(param_list.params().map(fmt_param));
211220
res_types.extend(param_list.params().map(|param| {
212221
let param_text = param.syntax().text().to_string();
213222
match param_text.split(':').nth(1).and_then(|it| it.get(1..)) {

0 commit comments

Comments
 (0)