aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api')
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs36
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs229
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs24
-rw-r--r--crates/ra_ide_api/src/display.rs8
4 files changed, 295 insertions, 2 deletions
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index d6b5ac9ad..55c78d305 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -587,4 +587,40 @@ mod tests {
587]"### 587]"###
588 ); 588 );
589 } 589 }
590
591 #[test]
592 fn completes_quantified_macros() {
593 assert_debug_snapshot!(
594 do_reference_completion(
595 "
596 #[macro_export]
597 macro_rules! foo {
598 () => {}
599 }
600
601 fn main() {
602 let _ = crate::<|>
603 }
604 "
605 ),
606 @r###"[
607 CompletionItem {
608 label: "foo",
609 source_range: [179; 179),
610 delete: [179; 179),
611 insert: "foo!",
612 kind: Macro,
613 detail: "#[macro_export]\nmacro_rules! foo",
614 },
615 CompletionItem {
616 label: "main",
617 source_range: [179; 179),
618 delete: [179; 179),
619 insert: "main()$0",
620 kind: Function,
621 detail: "fn main()",
622 },
623]"###
624 );
625 }
590} 626}
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 67fb7ba4e..e2e1d7872 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -6,6 +6,15 @@ use rustc_hash::FxHashMap;
6use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; 6use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions};
7 7
8pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { 8pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
9 // Show only macros in top level.
10 if ctx.is_new_item {
11 for (name, res) in ctx.analyzer.all_names(ctx.db) {
12 if res.get_macros().is_some() {
13 acc.add_resolution(ctx, name.to_string(), &res.only_macros());
14 }
15 }
16 }
17
9 if !ctx.is_trivial_path { 18 if !ctx.is_trivial_path {
10 return; 19 return;
11 } 20 }
@@ -532,4 +541,224 @@ mod tests {
532]"# 541]"#
533 ); 542 );
534 } 543 }
544
545 #[test]
546 fn completes_macros_as_value() {
547 assert_debug_snapshot!(
548 do_reference_completion(
549 "
550 //- /main.rs
551 macro_rules! foo {
552 () => {}
553 }
554
555 #[macro_use]
556 mod m1 {
557 macro_rules! bar {
558 () => {}
559 }
560 }
561
562 mod m2 {
563 macro_rules! nope {
564 () => {}
565 }
566
567 #[macro_export]
568 macro_rules! baz {
569 () => {}
570 }
571 }
572
573 fn main() {
574 let v = <|>
575 }
576 "
577 ),
578 @r##"[
579 CompletionItem {
580 label: "bar",
581 source_range: [252; 252),
582 delete: [252; 252),
583 insert: "bar!",
584 kind: Macro,
585 detail: "macro_rules! bar",
586 },
587 CompletionItem {
588 label: "baz",
589 source_range: [252; 252),
590 delete: [252; 252),
591 insert: "baz!",
592 kind: Macro,
593 detail: "#[macro_export]\nmacro_rules! baz",
594 },
595 CompletionItem {
596 label: "foo",
597 source_range: [252; 252),
598 delete: [252; 252),
599 insert: "foo!",
600 kind: Macro,
601 detail: "macro_rules! foo",
602 },
603 CompletionItem {
604 label: "m1",
605 source_range: [252; 252),
606 delete: [252; 252),
607 insert: "m1",
608 kind: Module,
609 },
610 CompletionItem {
611 label: "m2",
612 source_range: [252; 252),
613 delete: [252; 252),
614 insert: "m2",
615 kind: Module,
616 },
617 CompletionItem {
618 label: "main",
619 source_range: [252; 252),
620 delete: [252; 252),
621 insert: "main()$0",
622 kind: Function,
623 detail: "fn main()",
624 },
625]"##
626 );
627 }
628
629 #[test]
630 fn completes_both_macro_and_value() {
631 assert_debug_snapshot!(
632 do_reference_completion(
633 "
634 //- /main.rs
635 macro_rules! foo {
636 () => {}
637 }
638
639 fn foo() {
640 <|>
641 }
642 "
643 ),
644 @r##"[
645 CompletionItem {
646 label: "foo",
647 source_range: [49; 49),
648 delete: [49; 49),
649 insert: "foo!",
650 kind: Macro,
651 detail: "macro_rules! foo",
652 },
653 CompletionItem {
654 label: "foo",
655 source_range: [49; 49),
656 delete: [49; 49),
657 insert: "foo()$0",
658 kind: Function,
659 detail: "fn foo()",
660 },
661]"##
662 );
663 }
664
665 #[test]
666 fn completes_macros_as_type() {
667 assert_debug_snapshot!(
668 do_reference_completion(
669 "
670 //- /main.rs
671 macro_rules! foo {
672 () => {}
673 }
674
675 fn main() {
676 let x: <|>
677 }
678 "
679 ),
680 @r##"[
681 CompletionItem {
682 label: "foo",
683 source_range: [57; 57),
684 delete: [57; 57),
685 insert: "foo!",
686 kind: Macro,
687 detail: "macro_rules! foo",
688 },
689 CompletionItem {
690 label: "main",
691 source_range: [57; 57),
692 delete: [57; 57),
693 insert: "main()$0",
694 kind: Function,
695 detail: "fn main()",
696 },
697]"##
698 );
699 }
700
701 #[test]
702 fn completes_macros_as_stmt() {
703 assert_debug_snapshot!(
704 do_reference_completion(
705 "
706 //- /main.rs
707 macro_rules! foo {
708 () => {}
709 }
710
711 fn main() {
712 <|>
713 }
714 "
715 ),
716 @r##"[
717 CompletionItem {
718 label: "foo",
719 source_range: [50; 50),
720 delete: [50; 50),
721 insert: "foo!",
722 kind: Macro,
723 detail: "macro_rules! foo",
724 },
725 CompletionItem {
726 label: "main",
727 source_range: [50; 50),
728 delete: [50; 50),
729 insert: "main()$0",
730 kind: Function,
731 detail: "fn main()",
732 },
733]"##
734 );
735 }
736
737 #[test]
738 fn completes_macros_as_item() {
739 assert_debug_snapshot!(
740 do_reference_completion(
741 "
742 //- /main.rs
743 macro_rules! foo {
744 () => {}
745 }
746
747 fn foo() {}
748
749 <|>
750 "
751 ),
752 @r##"[
753 CompletionItem {
754 label: "foo",
755 source_range: [46; 46),
756 delete: [46; 46),
757 insert: "foo!",
758 kind: Macro,
759 detail: "macro_rules! foo",
760 },
761]"##
762 );
763 }
535} 764}
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index db7e8348e..1b706bb13 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -8,7 +8,7 @@ use crate::completion::{
8 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 8 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
9}; 9};
10 10
11use crate::display::{const_label, function_label, type_label}; 11use crate::display::{const_label, function_label, macro_label, type_label};
12 12
13impl Completions { 13impl Completions {
14 pub(crate) fn add_field( 14 pub(crate) fn add_field(
@@ -43,8 +43,14 @@ impl Completions {
43 ) { 43 ) {
44 use hir::ModuleDef::*; 44 use hir::ModuleDef::*;
45 45
46 if let Some(macro_) = resolution.get_macros() {
47 self.add_macro(ctx, Some(local_name.clone()), macro_);
48 }
49
46 let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values()); 50 let def = resolution.as_ref().take_types().or_else(|| resolution.as_ref().take_values());
47 let def = match def { 51 let def = match def {
52 // Only insert once if it is just a macro name
53 None if resolution.get_macros().is_some() => return,
48 None => { 54 None => {
49 self.add(CompletionItem::new( 55 self.add(CompletionItem::new(
50 CompletionKind::Reference, 56 CompletionKind::Reference,
@@ -98,6 +104,22 @@ impl Completions {
98 self.add_function_with_name(ctx, None, func) 104 self.add_function_with_name(ctx, None, func)
99 } 105 }
100 106
107 fn add_macro(&mut self, ctx: &CompletionContext, name: Option<String>, macro_: hir::MacroDef) {
108 let ast_node = macro_.source(ctx.db).ast;
109 if let Some(name) = name {
110 let detail = macro_label(&ast_node);
111
112 let builder =
113 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
114 .kind(CompletionItemKind::Macro)
115 .set_documentation(macro_.docs(ctx.db))
116 .detail(detail)
117 .insert_snippet(format!("{}!", name));
118
119 self.add(builder);
120 }
121 }
122
101 fn add_function_with_name( 123 fn add_function_with_name(
102 &mut self, 124 &mut self,
103 ctx: &CompletionContext, 125 ctx: &CompletionContext,
diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs
index cc59e99d8..a980c56bc 100644
--- a/crates/ra_ide_api/src/display.rs
+++ b/crates/ra_ide_api/src/display.rs
@@ -7,7 +7,7 @@ mod structure;
7mod short_label; 7mod short_label;
8 8
9use ra_syntax::{ 9use ra_syntax::{
10 ast::{self, AstNode, TypeParamsOwner}, 10 ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner},
11 SyntaxKind::{ATTR, COMMENT}, 11 SyntaxKind::{ATTR, COMMENT},
12}; 12};
13 13
@@ -61,6 +61,12 @@ pub(crate) fn where_predicates<N: TypeParamsOwner>(node: &N) -> Vec<String> {
61 res 61 res
62} 62}
63 63
64pub(crate) fn macro_label(node: &ast::MacroCall) -> String {
65 let name = node.name().map(|name| name.syntax().text().to_string()).unwrap_or_default();
66 let vis = if node.has_atom_attr("macro_export") { "#[macro_export]\n" } else { "" };
67 format!("{}macro_rules! {}", vis, name)
68}
69
64pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String { 70pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String {
65 rust_code_markup_with_doc::<_, &str>(val, None) 71 rust_code_markup_with_doc::<_, &str>(val, None)
66} 72}