Skip to content

Commit d454e77

Browse files
committed
add completions for clippy lint in attributes
Signed-off-by: Benjamin Coenen <[email protected]>
1 parent 518f6d7 commit d454e77

File tree

8 files changed

+142
-188
lines changed

8 files changed

+142
-188
lines changed

crates/ide/src/completion.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ mod completion_item;
33
mod completion_context;
44
mod presentation;
55
mod patterns;
6-
mod generated_features;
6+
mod generated_lint_completions;
77
#[cfg(test)]
88
mod test_utils;
99

crates/ide/src/completion/complete_attribute.rs

+4-127
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use syntax::{ast, AstNode, SyntaxKind};
99
use crate::completion::{
1010
completion_context::CompletionContext,
1111
completion_item::{CompletionItem, CompletionItemKind, CompletionKind, Completions},
12-
generated_features::FEATURES,
12+
generated_lint_completions::{CLIPPY_LINTS, FEATURES},
1313
};
1414

1515
pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> {
@@ -23,14 +23,15 @@ pub(super) fn complete_attribute(acc: &mut Completions, ctx: &CompletionContext)
2323
complete_derive(acc, ctx, token_tree)
2424
}
2525
(Some(path), Some(token_tree)) if path.to_string() == "feature" => {
26-
complete_lint(acc, ctx, token_tree, FEATURES)
26+
complete_lint(acc, ctx, token_tree, FEATURES);
2727
}
2828
(Some(path), Some(token_tree))
2929
if ["allow", "warn", "deny", "forbid"]
3030
.iter()
3131
.any(|lint_level| lint_level == &path.to_string()) =>
3232
{
33-
complete_lint(acc, ctx, token_tree, DEFAULT_LINT_COMPLETIONS)
33+
complete_lint(acc, ctx, token_tree.clone(), DEFAULT_LINT_COMPLETIONS);
34+
complete_lint(acc, ctx, token_tree, CLIPPY_LINTS);
3435
}
3536
(_, Some(_token_tree)) => {}
3637
_ => complete_attribute_start(acc, ctx, attribute),
@@ -417,130 +418,6 @@ struct Test {}
417418
);
418419
}
419420

420-
#[test]
421-
fn empty_lint_completion() {
422-
check(
423-
r#"#[allow(<|>)]"#,
424-
expect![[r#"
425-
at absolute_paths_not_starting_with_crate fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name
426-
at ambiguous_associated_items ambiguous associated items
427-
at anonymous_parameters detects anonymous parameters
428-
at arithmetic_overflow arithmetic operation overflows
429-
at array_into_iter detects calling `into_iter` on arrays
430-
at asm_sub_register using only a subset of a register for inline asm inputs
431-
at bare_trait_objects suggest using `dyn Trait` for trait objects
432-
at bindings_with_variant_name detects pattern bindings with the same name as one of the matched variants
433-
at box_pointers use of owned (Box type) heap memory
434-
at cenum_impl_drop_cast a C-like enum implementing Drop is cast
435-
at clashing_extern_declarations detects when an extern fn has been declared with the same name but different types
436-
at coherence_leak_check distinct impls distinguished only by the leak-check code
437-
at conflicting_repr_hints conflicts between `#[repr(..)]` hints that were previously accepted and used in practice
438-
at confusable_idents detects visually confusable pairs between identifiers
439-
at const_err constant evaluation detected erroneous expression
440-
at dead_code detect unused, unexported items
441-
at deprecated detects use of deprecated items
442-
at deprecated_in_future detects use of items that will be deprecated in a future version
443-
at elided_lifetimes_in_paths hidden lifetime parameters in types are deprecated
444-
at ellipsis_inclusive_range_patterns `...` range patterns are deprecated
445-
at explicit_outlives_requirements outlives requirements can be inferred
446-
at exported_private_dependencies public interface leaks type from a private dependency
447-
at ill_formed_attribute_input ill-formed attribute inputs that were previously accepted and used in practice
448-
at illegal_floating_point_literal_pattern floating-point literals cannot be used in patterns
449-
at improper_ctypes proper use of libc types in foreign modules
450-
at improper_ctypes_definitions proper use of libc types in foreign item definitions
451-
at incomplete_features incomplete features that may function improperly in some or all cases
452-
at incomplete_include trailing content in included file
453-
at indirect_structural_match pattern with const indirectly referencing non-structural-match type
454-
at inline_no_sanitize detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`
455-
at intra_doc_link_resolution_failure failures in resolving intra-doc link targets
456-
at invalid_codeblock_attributes codeblock attribute looks a lot like a known one
457-
at invalid_type_param_default type parameter default erroneously allowed in invalid location
458-
at invalid_value an invalid value is being created (such as a NULL reference)
459-
at irrefutable_let_patterns detects irrefutable patterns in if-let and while-let statements
460-
at keyword_idents detects edition keywords being used as an identifier
461-
at late_bound_lifetime_arguments detects generic lifetime arguments in path segments with late bound lifetime parameters
462-
at macro_expanded_macro_exports_accessed_by_absolute_paths macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
463-
at macro_use_extern_crate the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system
464-
at meta_variable_misuse possible meta-variable misuse at macro definition
465-
at missing_copy_implementations detects potentially-forgotten implementations of `Copy`
466-
at missing_crate_level_docs detects crates with no crate-level documentation
467-
at missing_debug_implementations detects missing implementations of Debug
468-
at missing_doc_code_examples detects publicly-exported items without code samples in their documentation
469-
at missing_docs detects missing documentation for public members
470-
at missing_fragment_specifier detects missing fragment specifiers in unused `macro_rules!` patterns
471-
at mixed_script_confusables detects Unicode scripts whose mixed script confusables codepoints are solely used
472-
at mutable_borrow_reservation_conflict reservation of a two-phased borrow conflicts with other shared borrows
473-
at mutable_transmutes mutating transmuted &mut T from &T may cause undefined behavior
474-
at no_mangle_const_items const items will not have their symbols exported
475-
at no_mangle_generic_items generic items must be mangled
476-
at non_ascii_idents detects non-ASCII identifiers
477-
at non_camel_case_types types, variants, traits and type parameters should have camel case names
478-
at non_shorthand_field_patterns using `Struct { x: x }` instead of `Struct { x }` in a pattern
479-
at non_snake_case variables, methods, functions, lifetime parameters and modules should have snake case names
480-
at non_upper_case_globals static constants should have uppercase identifiers
481-
at order_dependent_trait_objects trait-object types were treated as different depending on marker-trait order
482-
at overflowing_literals literal out of range for its type
483-
at overlapping_patterns detects overlapping patterns
484-
at path_statements path statements with no effect
485-
at patterns_in_fns_without_body patterns in functions without body were erroneously allowed
486-
at private_doc_tests detects code samples in docs of private items not documented by rustdoc
487-
at private_in_public detect private items in public interfaces not caught by the old implementation
488-
at proc_macro_derive_resolution_fallback detects proc macro derives using inaccessible names from parent modules
489-
at pub_use_of_private_extern_crate detect public re-exports of private extern crates
490-
at redundant_semicolons detects unnecessary trailing semicolons
491-
at renamed_and_removed_lints lints that have been renamed or removed
492-
at safe_packed_borrows safe borrows of fields of packed structs were erroneously allowed
493-
at single_use_lifetimes detects lifetime parameters that are only used once
494-
at soft_unstable a feature gate that doesn't break dependent crates
495-
at stable_features stable features found in `#[feature]` directive
496-
at trivial_bounds these bounds don't depend on an type parameters
497-
at trivial_casts detects trivial casts which could be removed
498-
at trivial_numeric_casts detects trivial casts of numeric types which could be removed
499-
at type_alias_bounds bounds in type aliases are not enforced
500-
at tyvar_behind_raw_pointer raw pointer to an inference variable
501-
at unaligned_references detects unaligned references to fields of packed structs
502-
at uncommon_codepoints detects uncommon Unicode codepoints in identifiers
503-
at unconditional_panic operation will cause a panic at runtime
504-
at unconditional_recursion functions that cannot return without calling themselves
505-
at unknown_crate_types unknown crate type found in `#[crate_type]` directive
506-
at unknown_lints unrecognized lint attribute
507-
at unnameable_test_items detects an item that cannot be named being marked as `#[test_case]`
508-
at unreachable_code detects unreachable code paths
509-
at unreachable_patterns detects unreachable patterns
510-
at unreachable_pub `pub` items not reachable from crate root
511-
at unsafe_code usage of `unsafe` code
512-
at unsafe_op_in_unsafe_fn unsafe operations in unsafe functions without an explicit unsafe block are deprecated
513-
at unstable_features enabling unstable features (deprecated. do not use)
514-
at unstable_name_collisions detects name collision with an existing but unstable method
515-
at unused_allocation detects unnecessary allocations that can be eliminated
516-
at unused_assignments detect assignments that will never be read
517-
at unused_attributes detects attributes that were not used by the compiler
518-
at unused_braces unnecessary braces around an expression
519-
at unused_comparisons comparisons made useless by limits of the types involved
520-
at unused_crate_dependencies crate dependencies that are never used
521-
at unused_doc_comments detects doc comments that aren't used by rustdoc
522-
at unused_extern_crates extern crates that are never used
523-
at unused_features unused features found in crate-level `#[feature]` directives
524-
at unused_import_braces unnecessary braces around an imported item
525-
at unused_imports imports that are never used
526-
at unused_labels detects labels that are never used
527-
at unused_lifetimes detects lifetime parameters that are never used
528-
at unused_macros detects macros that were not used
529-
at unused_must_use unused result of a type flagged as `#[must_use]`
530-
at unused_mut detect mut variables which don't need to be mutable
531-
at unused_parens `if`, `match`, `while` and `return` do not need parentheses
532-
at unused_qualifications detects unnecessarily qualified names
533-
at unused_results unused result of an expression in a statement
534-
at unused_unsafe unnecessary use of an `unsafe` block
535-
at unused_variables detect variables which are not used in any way
536-
at variant_size_differences detects enums with widely varying variant sizes
537-
at warnings mass-change the level for lints which produce warnings
538-
at where_clauses_object_safety checks the object safety of where clauses
539-
at while_true suggest using `loop { }` instead of `while true { }`
540-
"#]],
541-
)
542-
}
543-
544421
#[test]
545422
fn no_completion_for_incorrect_derive() {
546423
check(

crates/ide/src/completion/generated_features.rs

-4
This file was deleted.

crates/ide/src/completion/generated_lint_completions.rs

+5
Large diffs are not rendered by default.

xtask/src/codegen.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ mod gen_syntax;
99
mod gen_parser_tests;
1010
mod gen_assists_docs;
1111
mod gen_feature_docs;
12-
mod gen_features;
12+
mod gen_lint_completions;
1313

1414
use std::{
1515
fmt, mem,
@@ -25,7 +25,7 @@ use crate::{
2525
pub use self::{
2626
gen_assists_docs::{generate_assists_docs, generate_assists_tests},
2727
gen_feature_docs::generate_feature_docs,
28-
gen_features::generate_features,
28+
gen_lint_completions::generate_lint_completions,
2929
gen_parser_tests::generate_parser_tests,
3030
gen_syntax::generate_syntax,
3131
};
@@ -43,7 +43,7 @@ pub struct CodegenCmd {
4343
impl CodegenCmd {
4444
pub fn run(self) -> Result<()> {
4545
if self.features {
46-
generate_features(Mode::Overwrite)?;
46+
generate_lint_completions(Mode::Overwrite)?;
4747
}
4848
generate_syntax(Mode::Overwrite)?;
4949
generate_parser_tests(Mode::Overwrite)?;

xtask/src/codegen/gen_features.rs

-50
This file was deleted.
+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
//! Generates descriptors structure for unstable feature from Unstable Book
2+
use std::{
3+
collections::HashMap,
4+
fs::File,
5+
io::BufReader,
6+
io::Read,
7+
path::{Path, PathBuf},
8+
};
9+
10+
use quote::quote;
11+
use walkdir::WalkDir;
12+
13+
use crate::{
14+
codegen::{project_root, reformat, update, Mode, Result},
15+
not_bash::{fs2, run},
16+
run_rustfmt,
17+
};
18+
19+
pub fn generate_lint_completions(mode: Mode) -> Result<()> {
20+
if !Path::new("./target/rust").exists() {
21+
run!("git clone https://github.com/rust-lang/rust ./target/rust")?;
22+
}
23+
24+
let ts_features = generate_descriptor("./target/rust/src/doc/unstable-book/src".into())?;
25+
run!("curl http://rust-lang.github.io/rust-clippy/master/lints.json --output ./target/clippy_lints.json")?;
26+
27+
let ts_clippy = generate_descriptor_clippy("./target/clippy_lints.json")?;
28+
let ts = quote! {
29+
use crate::completion::complete_attribute::LintCompletion;
30+
#ts_features
31+
#ts_clippy
32+
};
33+
let contents = reformat(ts)?;
34+
35+
let destination =
36+
project_root().join("crates/ide/src/completion/generated_lint_completions.rs");
37+
update(destination.as_path(), &contents, mode)?;
38+
run_rustfmt(mode)?;
39+
40+
Ok(())
41+
}
42+
43+
fn generate_descriptor(src_dir: PathBuf) -> Result<proc_macro2::TokenStream> {
44+
let definitions = ["language-features", "library-features"]
45+
.iter()
46+
.flat_map(|it| WalkDir::new(src_dir.join(it)))
47+
.filter_map(|e| e.ok())
48+
.filter(|entry| {
49+
// Get all `.md ` files
50+
entry.file_type().is_file() && entry.path().extension().unwrap_or_default() == "md"
51+
})
52+
.map(|entry| {
53+
let path = entry.path();
54+
let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace("-", "_");
55+
let doc = fs2::read_to_string(path).unwrap();
56+
57+
quote! { LintCompletion { label: #feature_ident, description: #doc } }
58+
});
59+
60+
let ts = quote! {
61+
pub(super) const FEATURES: &[LintCompletion] = &[
62+
#(#definitions),*
63+
];
64+
};
65+
66+
Ok(ts)
67+
}
68+
69+
#[derive(Default)]
70+
struct ClippyLint {
71+
help: String,
72+
id: String,
73+
}
74+
75+
fn generate_descriptor_clippy(uri: &str) -> Result<proc_macro2::TokenStream> {
76+
let mut file = File::open(uri)?;
77+
let mut file_content = String::new();
78+
file.read_to_string(&mut file_content)?;
79+
let mut clippy_lints: Vec<ClippyLint> = vec![];
80+
81+
for line in file_content.lines().map(|line| line.trim()) {
82+
if line.starts_with(r#""id":"#) {
83+
let clippy_lint = ClippyLint {
84+
id: line
85+
.strip_prefix(r#""id": ""#)
86+
.expect("should be prefixed by id")
87+
.strip_suffix(r#"","#)
88+
.expect("should be suffixed by comma")
89+
.into(),
90+
help: String::new(),
91+
};
92+
clippy_lints.push(clippy_lint)
93+
} else if line.starts_with(r#""What it does":"#) {
94+
clippy_lints.last_mut().expect("clippy lint must already exist").help = line
95+
.strip_prefix(r#""What it does": ""#)
96+
.expect("should be prefixed by what it does")
97+
.strip_suffix(r#"","#)
98+
.expect("should be suffixed by comma")
99+
.into();
100+
}
101+
}
102+
103+
let definitions = clippy_lints.into_iter().map(|clippy_lint| {
104+
let lint_ident = format!("clippy::{}", clippy_lint.id);
105+
let doc = clippy_lint.help;
106+
107+
quote! { LintCompletion { label: #lint_ident, description: #doc } }
108+
});
109+
110+
let ts = quote! {
111+
pub(super) const CLIPPY_LINTS: &[LintCompletion] = &[
112+
#(#definitions),*
113+
];
114+
};
115+
116+
Ok(ts)
117+
}

0 commit comments

Comments
 (0)