diff options
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_path.rs | 36 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_scope.rs | 229 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/presentation.rs | 24 | ||||
-rw-r--r-- | crates/ra_ide_api/src/display.rs | 8 |
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; | |||
6 | use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; | 6 | use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions}; |
7 | 7 | ||
8 | pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) { | 8 | pub(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 | ||
11 | use crate::display::{const_label, function_label, type_label}; | 11 | use crate::display::{const_label, function_label, macro_label, type_label}; |
12 | 12 | ||
13 | impl Completions { | 13 | impl 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; | |||
7 | mod short_label; | 7 | mod short_label; |
8 | 8 | ||
9 | use ra_syntax::{ | 9 | use 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 | ||
64 | pub(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 | |||
64 | pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String { | 70 | pub(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 | } |