aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_completion/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_completion/src')
-rw-r--r--crates/ide_completion/src/completions/attribute.rs374
-rw-r--r--crates/ide_completion/src/completions/attribute/derive.rs141
-rw-r--r--crates/ide_completion/src/completions/attribute/lint.rs153
3 files changed, 302 insertions, 366 deletions
diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs
index 0997302a6..e128e307c 100644
--- a/crates/ide_completion/src/completions/attribute.rs
+++ b/crates/ide_completion/src/completions/attribute.rs
@@ -3,7 +3,6 @@
3//! This module uses a bit of static metadata to provide completions 3//! This module uses a bit of static metadata to provide completions
4//! for built-in attributes. 4//! for built-in attributes.
5 5
6use itertools::Itertools;
7use once_cell::sync::Lazy; 6use once_cell::sync::Lazy;
8use rustc_hash::{FxHashMap, FxHashSet}; 7use rustc_hash::{FxHashMap, FxHashSet};
9use syntax::{ast, AstNode, SyntaxKind, T}; 8use syntax::{ast, AstNode, SyntaxKind, T};
@@ -15,6 +14,10 @@ use crate::{
15 Completions, 14 Completions,
16}; 15};
17 16
17mod derive;
18mod lint;
19pub(crate) use self::lint::LintCompletion;
20
18pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { 21pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
19 if ctx.mod_declaration_under_caret.is_some() { 22 if ctx.mod_declaration_under_caret.is_some() {
20 return None; 23 return None;
@@ -23,11 +26,11 @@ pub(crate) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
23 let attribute = ctx.attribute_under_caret.as_ref()?; 26 let attribute = ctx.attribute_under_caret.as_ref()?;
24 match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) { 27 match (attribute.path().and_then(|p| p.as_single_name_ref()), attribute.token_tree()) {
25 (Some(path), Some(token_tree)) => match path.text().as_str() { 28 (Some(path), Some(token_tree)) => match path.text().as_str() {
26 "derive" => complete_derive(acc, ctx, token_tree), 29 "derive" => derive::complete_derive(acc, ctx, token_tree),
27 "feature" => complete_lint(acc, ctx, token_tree, FEATURES), 30 "feature" => lint::complete_lint(acc, ctx, token_tree, FEATURES),
28 "allow" | "warn" | "deny" | "forbid" => { 31 "allow" | "warn" | "deny" | "forbid" => {
29 complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS); 32 lint::complete_lint(acc, ctx, token_tree.clone(), lint::DEFAULT_LINT_COMPLETIONS);
30 complete_lint(acc, ctx, token_tree, CLIPPY_LINTS); 33 lint::complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
31 } 34 }
32 _ => (), 35 _ => (),
33 }, 36 },
@@ -246,61 +249,6 @@ fn attributes_are_sorted() {
246 }); 249 });
247} 250}
248 251
249fn complete_derive(acc: &mut Completions, ctx: &CompletionContext, derive_input: ast::TokenTree) {
250 if let Ok(existing_derives) = parse_comma_sep_input(derive_input) {
251 for derive_completion in DEFAULT_DERIVE_COMPLETIONS
252 .iter()
253 .filter(|completion| !existing_derives.contains(completion.label))
254 {
255 let mut components = vec![derive_completion.label];
256 components.extend(
257 derive_completion
258 .dependencies
259 .iter()
260 .filter(|&&dependency| !existing_derives.contains(dependency)),
261 );
262 let lookup = components.join(", ");
263 let label = components.iter().rev().join(", ");
264 let mut item =
265 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
266 item.lookup_by(lookup).kind(CompletionItemKind::Attribute);
267 item.add_to(acc);
268 }
269
270 for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) {
271 let mut item = CompletionItem::new(
272 CompletionKind::Attribute,
273 ctx.source_range(),
274 custom_derive_name,
275 );
276 item.kind(CompletionItemKind::Attribute);
277 item.add_to(acc);
278 }
279 }
280}
281
282fn complete_lint(
283 acc: &mut Completions,
284 ctx: &CompletionContext,
285 derive_input: ast::TokenTree,
286 lints_completions: &[LintCompletion],
287) {
288 if let Ok(existing_lints) = parse_comma_sep_input(derive_input) {
289 for lint_completion in lints_completions
290 .into_iter()
291 .filter(|completion| !existing_lints.contains(completion.label))
292 {
293 let mut item = CompletionItem::new(
294 CompletionKind::Attribute,
295 ctx.source_range(),
296 lint_completion.label,
297 );
298 item.kind(CompletionItemKind::Attribute).detail(lint_completion.description);
299 item.add_to(acc)
300 }
301 }
302}
303
304fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> { 252fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<String>, ()> {
305 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) { 253 match (derive_input.left_delimiter_token(), derive_input.right_delimiter_token()) {
306 (Some(left_paren), Some(right_paren)) 254 (Some(left_paren), Some(right_paren))
@@ -335,162 +283,6 @@ fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<Strin
335 } 283 }
336} 284}
337 285
338fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
339 let mut result = FxHashSet::default();
340 ctx.scope.process_all_names(&mut |name, scope_def| {
341 if let hir::ScopeDef::MacroDef(mac) = scope_def {
342 // FIXME kind() doesn't check whether proc-macro is a derive
343 if mac.kind() == hir::MacroKind::Derive || mac.kind() == hir::MacroKind::ProcMacro {
344 result.insert(name.to_string());
345 }
346 }
347 });
348 result
349}
350
351struct DeriveCompletion {
352 label: &'static str,
353 dependencies: &'static [&'static str],
354}
355
356/// Standard Rust derives and the information about their dependencies
357/// (the dependencies are needed so that the main derive don't break the compilation when added)
358const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
359 DeriveCompletion { label: "Clone", dependencies: &[] },
360 DeriveCompletion { label: "Copy", dependencies: &["Clone"] },
361 DeriveCompletion { label: "Debug", dependencies: &[] },
362 DeriveCompletion { label: "Default", dependencies: &[] },
363 DeriveCompletion { label: "Hash", dependencies: &[] },
364 DeriveCompletion { label: "PartialEq", dependencies: &[] },
365 DeriveCompletion { label: "Eq", dependencies: &["PartialEq"] },
366 DeriveCompletion { label: "PartialOrd", dependencies: &["PartialEq"] },
367 DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
368];
369
370pub(crate) struct LintCompletion {
371 pub(crate) label: &'static str,
372 pub(crate) description: &'static str,
373}
374
375#[rustfmt::skip]
376const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
377 LintCompletion { label: "absolute_paths_not_starting_with_crate", description: r#"fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name"# },
378 LintCompletion { label: "anonymous_parameters", description: r#"detects anonymous parameters"# },
379 LintCompletion { label: "box_pointers", description: r#"use of owned (Box type) heap memory"# },
380 LintCompletion { label: "deprecated_in_future", description: r#"detects use of items that will be deprecated in a future version"# },
381 LintCompletion { label: "elided_lifetimes_in_paths", description: r#"hidden lifetime parameters in types are deprecated"# },
382 LintCompletion { label: "explicit_outlives_requirements", description: r#"outlives requirements can be inferred"# },
383 LintCompletion { label: "indirect_structural_match", description: r#"pattern with const indirectly referencing non-structural-match type"# },
384 LintCompletion { label: "keyword_idents", description: r#"detects edition keywords being used as an identifier"# },
385 LintCompletion { label: "macro_use_extern_crate", description: r#"the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system"# },
386 LintCompletion { label: "meta_variable_misuse", description: r#"possible meta-variable misuse at macro definition"# },
387 LintCompletion { label: "missing_copy_implementations", description: r#"detects potentially-forgotten implementations of `Copy`"# },
388 LintCompletion { label: "missing_crate_level_docs", description: r#"detects crates with no crate-level documentation"# },
389 LintCompletion { label: "missing_debug_implementations", description: r#"detects missing implementations of Debug"# },
390 LintCompletion { label: "missing_docs", description: r#"detects missing documentation for public members"# },
391 LintCompletion { label: "missing_doc_code_examples", description: r#"detects publicly-exported items without code samples in their documentation"# },
392 LintCompletion { label: "non_ascii_idents", description: r#"detects non-ASCII identifiers"# },
393 LintCompletion { label: "private_doc_tests", description: r#"detects code samples in docs of private items not documented by rustdoc"# },
394 LintCompletion { label: "single_use_lifetimes", description: r#"detects lifetime parameters that are only used once"# },
395 LintCompletion { label: "trivial_casts", description: r#"detects trivial casts which could be removed"# },
396 LintCompletion { label: "trivial_numeric_casts", description: r#"detects trivial casts of numeric types which could be removed"# },
397 LintCompletion { label: "unaligned_references", description: r#"detects unaligned references to fields of packed structs"# },
398 LintCompletion { label: "unreachable_pub", description: r#"`pub` items not reachable from crate root"# },
399 LintCompletion { label: "unsafe_code", description: r#"usage of `unsafe` code"# },
400 LintCompletion { label: "unsafe_op_in_unsafe_fn", description: r#"unsafe operations in unsafe functions without an explicit unsafe block are deprecated"# },
401 LintCompletion { label: "unstable_features", description: r#"enabling unstable features (deprecated. do not use)"# },
402 LintCompletion { label: "unused_crate_dependencies", description: r#"crate dependencies that are never used"# },
403 LintCompletion { label: "unused_extern_crates", description: r#"extern crates that are never used"# },
404 LintCompletion { label: "unused_import_braces", description: r#"unnecessary braces around an imported item"# },
405 LintCompletion { label: "unused_lifetimes", description: r#"detects lifetime parameters that are never used"# },
406 LintCompletion { label: "unused_qualifications", description: r#"detects unnecessarily qualified names"# },
407 LintCompletion { label: "unused_results", description: r#"unused result of an expression in a statement"# },
408 LintCompletion { label: "variant_size_differences", description: r#"detects enums with widely varying variant sizes"# },
409 LintCompletion { label: "array_into_iter", description: r#"detects calling `into_iter` on arrays"# },
410 LintCompletion { label: "asm_sub_register", description: r#"using only a subset of a register for inline asm inputs"# },
411 LintCompletion { label: "bare_trait_objects", description: r#"suggest using `dyn Trait` for trait objects"# },
412 LintCompletion { label: "bindings_with_variant_name", description: r#"detects pattern bindings with the same name as one of the matched variants"# },
413 LintCompletion { label: "cenum_impl_drop_cast", description: r#"a C-like enum implementing Drop is cast"# },
414 LintCompletion { label: "clashing_extern_declarations", description: r#"detects when an extern fn has been declared with the same name but different types"# },
415 LintCompletion { label: "coherence_leak_check", description: r#"distinct impls distinguished only by the leak-check code"# },
416 LintCompletion { label: "confusable_idents", description: r#"detects visually confusable pairs between identifiers"# },
417 LintCompletion { label: "dead_code", description: r#"detect unused, unexported items"# },
418 LintCompletion { label: "deprecated", description: r#"detects use of deprecated items"# },
419 LintCompletion { label: "ellipsis_inclusive_range_patterns", description: r#"`...` range patterns are deprecated"# },
420 LintCompletion { label: "exported_private_dependencies", description: r#"public interface leaks type from a private dependency"# },
421 LintCompletion { label: "illegal_floating_point_literal_pattern", description: r#"floating-point literals cannot be used in patterns"# },
422 LintCompletion { label: "improper_ctypes", description: r#"proper use of libc types in foreign modules"# },
423 LintCompletion { label: "improper_ctypes_definitions", description: r#"proper use of libc types in foreign item definitions"# },
424 LintCompletion { label: "incomplete_features", description: r#"incomplete features that may function improperly in some or all cases"# },
425 LintCompletion { label: "inline_no_sanitize", description: r#"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`"# },
426 LintCompletion { label: "intra_doc_link_resolution_failure", description: r#"failures in resolving intra-doc link targets"# },
427 LintCompletion { label: "invalid_codeblock_attributes", description: r#"codeblock attribute looks a lot like a known one"# },
428 LintCompletion { label: "invalid_value", description: r#"an invalid value is being created (such as a NULL reference)"# },
429 LintCompletion { label: "irrefutable_let_patterns", description: r#"detects irrefutable patterns in if-let and while-let statements"# },
430 LintCompletion { label: "late_bound_lifetime_arguments", description: r#"detects generic lifetime arguments in path segments with late bound lifetime parameters"# },
431 LintCompletion { label: "mixed_script_confusables", description: r#"detects Unicode scripts whose mixed script confusables codepoints are solely used"# },
432 LintCompletion { label: "mutable_borrow_reservation_conflict", description: r#"reservation of a two-phased borrow conflicts with other shared borrows"# },
433 LintCompletion { label: "non_camel_case_types", description: r#"types, variants, traits and type parameters should have camel case names"# },
434 LintCompletion { label: "non_shorthand_field_patterns", description: r#"using `Struct { x: x }` instead of `Struct { x }` in a pattern"# },
435 LintCompletion { label: "non_snake_case", description: r#"variables, methods, functions, lifetime parameters and modules should have snake case names"# },
436 LintCompletion { label: "non_upper_case_globals", description: r#"static constants should have uppercase identifiers"# },
437 LintCompletion { label: "no_mangle_generic_items", description: r#"generic items must be mangled"# },
438 LintCompletion { label: "overlapping_patterns", description: r#"detects overlapping patterns"# },
439 LintCompletion { label: "path_statements", description: r#"path statements with no effect"# },
440 LintCompletion { label: "private_in_public", description: r#"detect private items in public interfaces not caught by the old implementation"# },
441 LintCompletion { label: "proc_macro_derive_resolution_fallback", description: r#"detects proc macro derives using inaccessible names from parent modules"# },
442 LintCompletion { label: "redundant_semicolons", description: r#"detects unnecessary trailing semicolons"# },
443 LintCompletion { label: "renamed_and_removed_lints", description: r#"lints that have been renamed or removed"# },
444 LintCompletion { label: "safe_packed_borrows", description: r#"safe borrows of fields of packed structs were erroneously allowed"# },
445 LintCompletion { label: "stable_features", description: r#"stable features found in `#[feature]` directive"# },
446 LintCompletion { label: "trivial_bounds", description: r#"these bounds don't depend on an type parameters"# },
447 LintCompletion { label: "type_alias_bounds", description: r#"bounds in type aliases are not enforced"# },
448 LintCompletion { label: "tyvar_behind_raw_pointer", description: r#"raw pointer to an inference variable"# },
449 LintCompletion { label: "uncommon_codepoints", description: r#"detects uncommon Unicode codepoints in identifiers"# },
450 LintCompletion { label: "unconditional_recursion", description: r#"functions that cannot return without calling themselves"# },
451 LintCompletion { label: "unknown_lints", description: r#"unrecognized lint attribute"# },
452 LintCompletion { label: "unnameable_test_items", description: r#"detects an item that cannot be named being marked as `#[test_case]`"# },
453 LintCompletion { label: "unreachable_code", description: r#"detects unreachable code paths"# },
454 LintCompletion { label: "unreachable_patterns", description: r#"detects unreachable patterns"# },
455 LintCompletion { label: "unstable_name_collisions", description: r#"detects name collision with an existing but unstable method"# },
456 LintCompletion { label: "unused_allocation", description: r#"detects unnecessary allocations that can be eliminated"# },
457 LintCompletion { label: "unused_assignments", description: r#"detect assignments that will never be read"# },
458 LintCompletion { label: "unused_attributes", description: r#"detects attributes that were not used by the compiler"# },
459 LintCompletion { label: "unused_braces", description: r#"unnecessary braces around an expression"# },
460 LintCompletion { label: "unused_comparisons", description: r#"comparisons made useless by limits of the types involved"# },
461 LintCompletion { label: "unused_doc_comments", description: r#"detects doc comments that aren't used by rustdoc"# },
462 LintCompletion { label: "unused_features", description: r#"unused features found in crate-level `#[feature]` directives"# },
463 LintCompletion { label: "unused_imports", description: r#"imports that are never used"# },
464 LintCompletion { label: "unused_labels", description: r#"detects labels that are never used"# },
465 LintCompletion { label: "unused_macros", description: r#"detects macros that were not used"# },
466 LintCompletion { label: "unused_must_use", description: r#"unused result of a type flagged as `#[must_use]`"# },
467 LintCompletion { label: "unused_mut", description: r#"detect mut variables which don't need to be mutable"# },
468 LintCompletion { label: "unused_parens", description: r#"`if`, `match`, `while` and `return` do not need parentheses"# },
469 LintCompletion { label: "unused_unsafe", description: r#"unnecessary use of an `unsafe` block"# },
470 LintCompletion { label: "unused_variables", description: r#"detect variables which are not used in any way"# },
471 LintCompletion { label: "warnings", description: r#"mass-change the level for lints which produce warnings"# },
472 LintCompletion { label: "where_clauses_object_safety", description: r#"checks the object safety of where clauses"# },
473 LintCompletion { label: "while_true", description: r#"suggest using `loop { }` instead of `while true { }`"# },
474 LintCompletion { label: "ambiguous_associated_items", description: r#"ambiguous associated items"# },
475 LintCompletion { label: "arithmetic_overflow", description: r#"arithmetic operation overflows"# },
476 LintCompletion { label: "conflicting_repr_hints", description: r#"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice"# },
477 LintCompletion { label: "const_err", description: r#"constant evaluation detected erroneous expression"# },
478 LintCompletion { label: "ill_formed_attribute_input", description: r#"ill-formed attribute inputs that were previously accepted and used in practice"# },
479 LintCompletion { label: "incomplete_include", description: r#"trailing content in included file"# },
480 LintCompletion { label: "invalid_type_param_default", description: r#"type parameter default erroneously allowed in invalid location"# },
481 LintCompletion { label: "macro_expanded_macro_exports_accessed_by_absolute_paths", description: r#"macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths"# },
482 LintCompletion { label: "missing_fragment_specifier", description: r#"detects missing fragment specifiers in unused `macro_rules!` patterns"# },
483 LintCompletion { label: "mutable_transmutes", description: r#"mutating transmuted &mut T from &T may cause undefined behavior"# },
484 LintCompletion { label: "no_mangle_const_items", description: r#"const items will not have their symbols exported"# },
485 LintCompletion { label: "order_dependent_trait_objects", description: r#"trait-object types were treated as different depending on marker-trait order"# },
486 LintCompletion { label: "overflowing_literals", description: r#"literal out of range for its type"# },
487 LintCompletion { label: "patterns_in_fns_without_body", description: r#"patterns in functions without body were erroneously allowed"# },
488 LintCompletion { label: "pub_use_of_private_extern_crate", description: r#"detect public re-exports of private extern crates"# },
489 LintCompletion { label: "soft_unstable", description: r#"a feature gate that doesn't break dependent crates"# },
490 LintCompletion { label: "unconditional_panic", description: r#"operation will cause a panic at runtime"# },
491 LintCompletion { label: "unknown_crate_types", description: r#"unknown crate type found in `#[crate_type]` directive"# },
492];
493
494#[cfg(test)] 286#[cfg(test)]
495mod tests { 287mod tests {
496 use expect_test::{expect, Expect}; 288 use expect_test::{expect, Expect};
@@ -521,158 +313,8 @@ struct Test {}
521 "#]], 313 "#]],
522 ); 314 );
523 } 315 }
524
525 #[test]
526 fn empty_derive_completion() {
527 check(
528 r#"
529#[derive($0)]
530struct Test {}
531 "#,
532 expect![[r#"
533 at Clone
534 at Clone, Copy
535 at Debug
536 at Default
537 at Hash
538 at PartialEq
539 at PartialEq, Eq
540 at PartialEq, PartialOrd
541 at PartialEq, Eq, PartialOrd, Ord
542 "#]],
543 );
544 }
545
546 #[test]
547 fn no_completion_for_incorrect_derive() {
548 check(
549 r#"
550#[derive{$0)]
551struct Test {}
552"#,
553 expect![[r#""#]],
554 )
555 }
556
557 #[test]
558 fn derive_with_input_completion() {
559 check(
560 r#"
561#[derive(serde::Serialize, PartialEq, $0)]
562struct Test {}
563"#,
564 expect![[r#"
565 at Clone
566 at Clone, Copy
567 at Debug
568 at Default
569 at Hash
570 at Eq
571 at PartialOrd
572 at Eq, PartialOrd, Ord
573 "#]],
574 )
575 }
576
577 #[test]
578 fn test_attribute_completion() {
579 check(
580 r#"#[$0]"#,
581 expect![[r#"
582 at allow(…)
583 at automatically_derived
584 at cfg(…)
585 at cfg_attr(…)
586 at cold
587 at deny(…)
588 at deprecated
589 at derive(…)
590 at doc = "…"
591 at doc(alias = "…")
592 at doc(hidden)
593 at export_name = "…"
594 at forbid(…)
595 at ignore = "…"
596 at inline
597 at link
598 at link_name = "…"
599 at link_section = "…"
600 at macro_export
601 at macro_use
602 at must_use
603 at no_mangle
604 at non_exhaustive
605 at path = "…"
606 at proc_macro
607 at proc_macro_attribute
608 at proc_macro_derive(…)
609 at repr(…)
610 at should_panic
611 at target_feature = "…"
612 at test
613 at track_caller
614 at used
615 at warn(…)
616 "#]],
617 )
618 }
619
620 #[test] 316 #[test]
621 fn test_attribute_completion_inside_nested_attr() { 317 fn test_attribute_completion_inside_nested_attr() {
622 check(r#"#[cfg($0)]"#, expect![[]]) 318 check(r#"#[cfg($0)]"#, expect![[]])
623 } 319 }
624
625 #[test]
626 fn test_inner_attribute_completion() {
627 check(
628 r"#![$0]",
629 expect![[r#"
630 at allow(…)
631 at automatically_derived
632 at cfg(…)
633 at cfg_attr(…)
634 at cold
635 at crate_name = ""
636 at deny(…)
637 at deprecated
638 at derive(…)
639 at doc = "…"
640 at doc(alias = "…")
641 at doc(hidden)
642 at export_name = "…"
643 at feature(…)
644 at forbid(…)
645 at global_allocator
646 at ignore = "…"
647 at inline
648 at link
649 at link_name = "…"
650 at link_section = "…"
651 at macro_export
652 at macro_use
653 at must_use
654 at no_implicit_prelude
655 at no_link
656 at no_main
657 at no_mangle
658 at no_std
659 at non_exhaustive
660 at panic_handler
661 at path = "…"
662 at proc_macro
663 at proc_macro_attribute
664 at proc_macro_derive(…)
665 at recursion_limit = …
666 at repr(…)
667 at should_panic
668 at target_feature = "…"
669 at test
670 at track_caller
671 at type_length_limit = …
672 at used
673 at warn(…)
674 at windows_subsystem = "…"
675 "#]],
676 );
677 }
678} 320}
diff --git a/crates/ide_completion/src/completions/attribute/derive.rs b/crates/ide_completion/src/completions/attribute/derive.rs
new file mode 100644
index 000000000..c14b03ea4
--- /dev/null
+++ b/crates/ide_completion/src/completions/attribute/derive.rs
@@ -0,0 +1,141 @@
1use itertools::Itertools;
2use rustc_hash::FxHashSet;
3use syntax::ast;
4
5use crate::{
6 context::CompletionContext,
7 item::{CompletionItem, CompletionItemKind, CompletionKind},
8 Completions,
9};
10
11pub(super) fn complete_derive(
12 acc: &mut Completions,
13 ctx: &CompletionContext,
14 derive_input: ast::TokenTree,
15) {
16 if let Ok(existing_derives) = super::parse_comma_sep_input(derive_input) {
17 for derive_completion in DEFAULT_DERIVE_COMPLETIONS
18 .iter()
19 .filter(|completion| !existing_derives.contains(completion.label))
20 {
21 let mut components = vec![derive_completion.label];
22 components.extend(
23 derive_completion
24 .dependencies
25 .iter()
26 .filter(|&&dependency| !existing_derives.contains(dependency)),
27 );
28 let lookup = components.join(", ");
29 let label = components.iter().rev().join(", ");
30 let mut item =
31 CompletionItem::new(CompletionKind::Attribute, ctx.source_range(), label);
32 item.lookup_by(lookup).kind(CompletionItemKind::Attribute);
33 item.add_to(acc);
34 }
35
36 for custom_derive_name in get_derive_names_in_scope(ctx).difference(&existing_derives) {
37 let mut item = CompletionItem::new(
38 CompletionKind::Attribute,
39 ctx.source_range(),
40 custom_derive_name,
41 );
42 item.kind(CompletionItemKind::Attribute);
43 item.add_to(acc);
44 }
45 }
46}
47fn get_derive_names_in_scope(ctx: &CompletionContext) -> FxHashSet<String> {
48 let mut result = FxHashSet::default();
49 ctx.scope.process_all_names(&mut |name, scope_def| {
50 if let hir::ScopeDef::MacroDef(mac) = scope_def {
51 // FIXME kind() doesn't check whether proc-macro is a derive
52 if mac.kind() == hir::MacroKind::Derive || mac.kind() == hir::MacroKind::ProcMacro {
53 result.insert(name.to_string());
54 }
55 }
56 });
57 result
58}
59
60struct DeriveCompletion {
61 label: &'static str,
62 dependencies: &'static [&'static str],
63}
64
65/// Standard Rust derives and the information about their dependencies
66/// (the dependencies are needed so that the main derive don't break the compilation when added)
67const DEFAULT_DERIVE_COMPLETIONS: &[DeriveCompletion] = &[
68 DeriveCompletion { label: "Clone", dependencies: &[] },
69 DeriveCompletion { label: "Copy", dependencies: &["Clone"] },
70 DeriveCompletion { label: "Debug", dependencies: &[] },
71 DeriveCompletion { label: "Default", dependencies: &[] },
72 DeriveCompletion { label: "Hash", dependencies: &[] },
73 DeriveCompletion { label: "PartialEq", dependencies: &[] },
74 DeriveCompletion { label: "Eq", dependencies: &["PartialEq"] },
75 DeriveCompletion { label: "PartialOrd", dependencies: &["PartialEq"] },
76 DeriveCompletion { label: "Ord", dependencies: &["PartialOrd", "Eq", "PartialEq"] },
77];
78
79#[cfg(test)]
80mod tests {
81 use expect_test::{expect, Expect};
82
83 use crate::{test_utils::completion_list, CompletionKind};
84
85 fn check(ra_fixture: &str, expect: Expect) {
86 let actual = completion_list(ra_fixture, CompletionKind::Attribute);
87 expect.assert_eq(&actual);
88 }
89
90 #[test]
91 fn empty_derive_completion() {
92 check(
93 r#"
94#[derive($0)]
95struct Test {}
96 "#,
97 expect![[r#"
98 at Clone
99 at Clone, Copy
100 at Debug
101 at Default
102 at Hash
103 at PartialEq
104 at PartialEq, Eq
105 at PartialEq, PartialOrd
106 at PartialEq, Eq, PartialOrd, Ord
107 "#]],
108 );
109 }
110
111 #[test]
112 fn no_completion_for_incorrect_derive() {
113 check(
114 r#"
115#[derive{$0)]
116struct Test {}
117"#,
118 expect![[r#""#]],
119 )
120 }
121
122 #[test]
123 fn derive_with_input_completion() {
124 check(
125 r#"
126#[derive(serde::Serialize, PartialEq, $0)]
127struct Test {}
128"#,
129 expect![[r#"
130 at Clone
131 at Clone, Copy
132 at Debug
133 at Default
134 at Hash
135 at Eq
136 at PartialOrd
137 at Eq, PartialOrd, Ord
138 "#]],
139 )
140 }
141}
diff --git a/crates/ide_completion/src/completions/attribute/lint.rs b/crates/ide_completion/src/completions/attribute/lint.rs
new file mode 100644
index 000000000..1f9873d3c
--- /dev/null
+++ b/crates/ide_completion/src/completions/attribute/lint.rs
@@ -0,0 +1,153 @@
1use syntax::ast;
2
3use crate::{
4 context::CompletionContext,
5 item::{CompletionItem, CompletionItemKind, CompletionKind},
6 Completions,
7};
8
9pub(super) fn complete_lint(
10 acc: &mut Completions,
11 ctx: &CompletionContext,
12 derive_input: ast::TokenTree,
13 lints_completions: &[LintCompletion],
14) {
15 if let Ok(existing_lints) = super::parse_comma_sep_input(derive_input) {
16 for lint_completion in lints_completions
17 .into_iter()
18 .filter(|completion| !existing_lints.contains(completion.label))
19 {
20 let mut item = CompletionItem::new(
21 CompletionKind::Attribute,
22 ctx.source_range(),
23 lint_completion.label,
24 );
25 item.kind(CompletionItemKind::Attribute).detail(lint_completion.description);
26 item.add_to(acc)
27 }
28 }
29}
30
31pub(crate) struct LintCompletion {
32 pub(crate) label: &'static str,
33 pub(crate) description: &'static str,
34}
35
36#[rustfmt::skip]
37pub(super) const DEFAULT_LINT_COMPLETIONS: &[LintCompletion] = &[
38 LintCompletion { label: "absolute_paths_not_starting_with_crate", description: r#"fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name"# },
39 LintCompletion { label: "anonymous_parameters", description: r#"detects anonymous parameters"# },
40 LintCompletion { label: "box_pointers", description: r#"use of owned (Box type) heap memory"# },
41 LintCompletion { label: "deprecated_in_future", description: r#"detects use of items that will be deprecated in a future version"# },
42 LintCompletion { label: "elided_lifetimes_in_paths", description: r#"hidden lifetime parameters in types are deprecated"# },
43 LintCompletion { label: "explicit_outlives_requirements", description: r#"outlives requirements can be inferred"# },
44 LintCompletion { label: "indirect_structural_match", description: r#"pattern with const indirectly referencing non-structural-match type"# },
45 LintCompletion { label: "keyword_idents", description: r#"detects edition keywords being used as an identifier"# },
46 LintCompletion { label: "macro_use_extern_crate", description: r#"the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system"# },
47 LintCompletion { label: "meta_variable_misuse", description: r#"possible meta-variable misuse at macro definition"# },
48 LintCompletion { label: "missing_copy_implementations", description: r#"detects potentially-forgotten implementations of `Copy`"# },
49 LintCompletion { label: "missing_crate_level_docs", description: r#"detects crates with no crate-level documentation"# },
50 LintCompletion { label: "missing_debug_implementations", description: r#"detects missing implementations of Debug"# },
51 LintCompletion { label: "missing_docs", description: r#"detects missing documentation for public members"# },
52 LintCompletion { label: "missing_doc_code_examples", description: r#"detects publicly-exported items without code samples in their documentation"# },
53 LintCompletion { label: "non_ascii_idents", description: r#"detects non-ASCII identifiers"# },
54 LintCompletion { label: "private_doc_tests", description: r#"detects code samples in docs of private items not documented by rustdoc"# },
55 LintCompletion { label: "single_use_lifetimes", description: r#"detects lifetime parameters that are only used once"# },
56 LintCompletion { label: "trivial_casts", description: r#"detects trivial casts which could be removed"# },
57 LintCompletion { label: "trivial_numeric_casts", description: r#"detects trivial casts of numeric types which could be removed"# },
58 LintCompletion { label: "unaligned_references", description: r#"detects unaligned references to fields of packed structs"# },
59 LintCompletion { label: "unreachable_pub", description: r#"`pub` items not reachable from crate root"# },
60 LintCompletion { label: "unsafe_code", description: r#"usage of `unsafe` code"# },
61 LintCompletion { label: "unsafe_op_in_unsafe_fn", description: r#"unsafe operations in unsafe functions without an explicit unsafe block are deprecated"# },
62 LintCompletion { label: "unstable_features", description: r#"enabling unstable features (deprecated. do not use)"# },
63 LintCompletion { label: "unused_crate_dependencies", description: r#"crate dependencies that are never used"# },
64 LintCompletion { label: "unused_extern_crates", description: r#"extern crates that are never used"# },
65 LintCompletion { label: "unused_import_braces", description: r#"unnecessary braces around an imported item"# },
66 LintCompletion { label: "unused_lifetimes", description: r#"detects lifetime parameters that are never used"# },
67 LintCompletion { label: "unused_qualifications", description: r#"detects unnecessarily qualified names"# },
68 LintCompletion { label: "unused_results", description: r#"unused result of an expression in a statement"# },
69 LintCompletion { label: "variant_size_differences", description: r#"detects enums with widely varying variant sizes"# },
70 LintCompletion { label: "array_into_iter", description: r#"detects calling `into_iter` on arrays"# },
71 LintCompletion { label: "asm_sub_register", description: r#"using only a subset of a register for inline asm inputs"# },
72 LintCompletion { label: "bare_trait_objects", description: r#"suggest using `dyn Trait` for trait objects"# },
73 LintCompletion { label: "bindings_with_variant_name", description: r#"detects pattern bindings with the same name as one of the matched variants"# },
74 LintCompletion { label: "cenum_impl_drop_cast", description: r#"a C-like enum implementing Drop is cast"# },
75 LintCompletion { label: "clashing_extern_declarations", description: r#"detects when an extern fn has been declared with the same name but different types"# },
76 LintCompletion { label: "coherence_leak_check", description: r#"distinct impls distinguished only by the leak-check code"# },
77 LintCompletion { label: "confusable_idents", description: r#"detects visually confusable pairs between identifiers"# },
78 LintCompletion { label: "dead_code", description: r#"detect unused, unexported items"# },
79 LintCompletion { label: "deprecated", description: r#"detects use of deprecated items"# },
80 LintCompletion { label: "ellipsis_inclusive_range_patterns", description: r#"`...` range patterns are deprecated"# },
81 LintCompletion { label: "exported_private_dependencies", description: r#"public interface leaks type from a private dependency"# },
82 LintCompletion { label: "illegal_floating_point_literal_pattern", description: r#"floating-point literals cannot be used in patterns"# },
83 LintCompletion { label: "improper_ctypes", description: r#"proper use of libc types in foreign modules"# },
84 LintCompletion { label: "improper_ctypes_definitions", description: r#"proper use of libc types in foreign item definitions"# },
85 LintCompletion { label: "incomplete_features", description: r#"incomplete features that may function improperly in some or all cases"# },
86 LintCompletion { label: "inline_no_sanitize", description: r#"detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`"# },
87 LintCompletion { label: "intra_doc_link_resolution_failure", description: r#"failures in resolving intra-doc link targets"# },
88 LintCompletion { label: "invalid_codeblock_attributes", description: r#"codeblock attribute looks a lot like a known one"# },
89 LintCompletion { label: "invalid_value", description: r#"an invalid value is being created (such as a NULL reference)"# },
90 LintCompletion { label: "irrefutable_let_patterns", description: r#"detects irrefutable patterns in if-let and while-let statements"# },
91 LintCompletion { label: "late_bound_lifetime_arguments", description: r#"detects generic lifetime arguments in path segments with late bound lifetime parameters"# },
92 LintCompletion { label: "mixed_script_confusables", description: r#"detects Unicode scripts whose mixed script confusables codepoints are solely used"# },
93 LintCompletion { label: "mutable_borrow_reservation_conflict", description: r#"reservation of a two-phased borrow conflicts with other shared borrows"# },
94 LintCompletion { label: "non_camel_case_types", description: r#"types, variants, traits and type parameters should have camel case names"# },
95 LintCompletion { label: "non_shorthand_field_patterns", description: r#"using `Struct { x: x }` instead of `Struct { x }` in a pattern"# },
96 LintCompletion { label: "non_snake_case", description: r#"variables, methods, functions, lifetime parameters and modules should have snake case names"# },
97 LintCompletion { label: "non_upper_case_globals", description: r#"static constants should have uppercase identifiers"# },
98 LintCompletion { label: "no_mangle_generic_items", description: r#"generic items must be mangled"# },
99 LintCompletion { label: "overlapping_patterns", description: r#"detects overlapping patterns"# },
100 LintCompletion { label: "path_statements", description: r#"path statements with no effect"# },
101 LintCompletion { label: "private_in_public", description: r#"detect private items in public interfaces not caught by the old implementation"# },
102 LintCompletion { label: "proc_macro_derive_resolution_fallback", description: r#"detects proc macro derives using inaccessible names from parent modules"# },
103 LintCompletion { label: "redundant_semicolons", description: r#"detects unnecessary trailing semicolons"# },
104 LintCompletion { label: "renamed_and_removed_lints", description: r#"lints that have been renamed or removed"# },
105 LintCompletion { label: "safe_packed_borrows", description: r#"safe borrows of fields of packed structs were erroneously allowed"# },
106 LintCompletion { label: "stable_features", description: r#"stable features found in `#[feature]` directive"# },
107 LintCompletion { label: "trivial_bounds", description: r#"these bounds don't depend on an type parameters"# },
108 LintCompletion { label: "type_alias_bounds", description: r#"bounds in type aliases are not enforced"# },
109 LintCompletion { label: "tyvar_behind_raw_pointer", description: r#"raw pointer to an inference variable"# },
110 LintCompletion { label: "uncommon_codepoints", description: r#"detects uncommon Unicode codepoints in identifiers"# },
111 LintCompletion { label: "unconditional_recursion", description: r#"functions that cannot return without calling themselves"# },
112 LintCompletion { label: "unknown_lints", description: r#"unrecognized lint attribute"# },
113 LintCompletion { label: "unnameable_test_items", description: r#"detects an item that cannot be named being marked as `#[test_case]`"# },
114 LintCompletion { label: "unreachable_code", description: r#"detects unreachable code paths"# },
115 LintCompletion { label: "unreachable_patterns", description: r#"detects unreachable patterns"# },
116 LintCompletion { label: "unstable_name_collisions", description: r#"detects name collision with an existing but unstable method"# },
117 LintCompletion { label: "unused_allocation", description: r#"detects unnecessary allocations that can be eliminated"# },
118 LintCompletion { label: "unused_assignments", description: r#"detect assignments that will never be read"# },
119 LintCompletion { label: "unused_attributes", description: r#"detects attributes that were not used by the compiler"# },
120 LintCompletion { label: "unused_braces", description: r#"unnecessary braces around an expression"# },
121 LintCompletion { label: "unused_comparisons", description: r#"comparisons made useless by limits of the types involved"# },
122 LintCompletion { label: "unused_doc_comments", description: r#"detects doc comments that aren't used by rustdoc"# },
123 LintCompletion { label: "unused_features", description: r#"unused features found in crate-level `#[feature]` directives"# },
124 LintCompletion { label: "unused_imports", description: r#"imports that are never used"# },
125 LintCompletion { label: "unused_labels", description: r#"detects labels that are never used"# },
126 LintCompletion { label: "unused_macros", description: r#"detects macros that were not used"# },
127 LintCompletion { label: "unused_must_use", description: r#"unused result of a type flagged as `#[must_use]`"# },
128 LintCompletion { label: "unused_mut", description: r#"detect mut variables which don't need to be mutable"# },
129 LintCompletion { label: "unused_parens", description: r#"`if`, `match`, `while` and `return` do not need parentheses"# },
130 LintCompletion { label: "unused_unsafe", description: r#"unnecessary use of an `unsafe` block"# },
131 LintCompletion { label: "unused_variables", description: r#"detect variables which are not used in any way"# },
132 LintCompletion { label: "warnings", description: r#"mass-change the level for lints which produce warnings"# },
133 LintCompletion { label: "where_clauses_object_safety", description: r#"checks the object safety of where clauses"# },
134 LintCompletion { label: "while_true", description: r#"suggest using `loop { }` instead of `while true { }`"# },
135 LintCompletion { label: "ambiguous_associated_items", description: r#"ambiguous associated items"# },
136 LintCompletion { label: "arithmetic_overflow", description: r#"arithmetic operation overflows"# },
137 LintCompletion { label: "conflicting_repr_hints", description: r#"conflicts between `#[repr(..)]` hints that were previously accepted and used in practice"# },
138 LintCompletion { label: "const_err", description: r#"constant evaluation detected erroneous expression"# },
139 LintCompletion { label: "ill_formed_attribute_input", description: r#"ill-formed attribute inputs that were previously accepted and used in practice"# },
140 LintCompletion { label: "incomplete_include", description: r#"trailing content in included file"# },
141 LintCompletion { label: "invalid_type_param_default", description: r#"type parameter default erroneously allowed in invalid location"# },
142 LintCompletion { label: "macro_expanded_macro_exports_accessed_by_absolute_paths", description: r#"macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths"# },
143 LintCompletion { label: "missing_fragment_specifier", description: r#"detects missing fragment specifiers in unused `macro_rules!` patterns"# },
144 LintCompletion { label: "mutable_transmutes", description: r#"mutating transmuted &mut T from &T may cause undefined behavior"# },
145 LintCompletion { label: "no_mangle_const_items", description: r#"const items will not have their symbols exported"# },
146 LintCompletion { label: "order_dependent_trait_objects", description: r#"trait-object types were treated as different depending on marker-trait order"# },
147 LintCompletion { label: "overflowing_literals", description: r#"literal out of range for its type"# },
148 LintCompletion { label: "patterns_in_fns_without_body", description: r#"patterns in functions without body were erroneously allowed"# },
149 LintCompletion { label: "pub_use_of_private_extern_crate", description: r#"detect public re-exports of private extern crates"# },
150 LintCompletion { label: "soft_unstable", description: r#"a feature gate that doesn't break dependent crates"# },
151 LintCompletion { label: "unconditional_panic", description: r#"operation will cause a panic at runtime"# },
152 LintCompletion { label: "unknown_crate_types", description: r#"unknown crate type found in `#[crate_type]` directive"# },
153];