Skip to content

Commit 577f29d

Browse files
committed
add completions for clippy lint in attributes
Signed-off-by: Benjamin Coenen <[email protected]>
1 parent 636b413 commit 577f29d

10 files changed

+120
-188
lines changed

Cargo.lock

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

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/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,6 @@ ungrammar = "1.1.3"
1919
walkdir = "2.3.1"
2020
write-json = "0.1.0"
2121
fs-err = "2.3"
22+
serde = { version = "1.0", features = ["derive"] }
23+
serde_json = "1.0"
2224
# Avoid adding more dependencies to this crate

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.
+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//! Generates descriptors structure for unstable feature from Unstable Book
2+
use std::{
3+
collections::HashMap,
4+
fs::File,
5+
path::{Path, PathBuf},
6+
};
7+
8+
use quote::quote;
9+
use serde::Deserialize;
10+
use walkdir::WalkDir;
11+
12+
use crate::{
13+
codegen::{project_root, reformat, update, Mode, Result},
14+
not_bash::{fs2, run},
15+
run_rustfmt,
16+
};
17+
18+
pub fn generate_lint_completions(mode: Mode) -> Result<()> {
19+
if !Path::new("./target/rust").exists() {
20+
run!("git clone https://github.com/rust-lang/rust ./target/rust")?;
21+
}
22+
23+
let ts_features = generate_descriptor("./target/rust/src/doc/unstable-book/src".into())?;
24+
run!("curl http://rust-lang.github.io/rust-clippy/master/lints.json --output ./target/clippy_lints.json")?;
25+
26+
let ts_clippy = generate_descriptor_clippy("./target/clippy_lints.json")?;
27+
let ts = quote! {
28+
use crate::completion::complete_attribute::LintCompletion;
29+
#ts_features
30+
#ts_clippy
31+
};
32+
let contents = reformat(ts)?;
33+
34+
let destination =
35+
project_root().join("crates/ide/src/completion/generated_lint_completions.rs");
36+
update(destination.as_path(), &contents, mode)?;
37+
run_rustfmt(mode)?;
38+
39+
Ok(())
40+
}
41+
42+
fn generate_descriptor(src_dir: PathBuf) -> Result<proc_macro2::TokenStream> {
43+
let definitions = ["language-features", "library-features"]
44+
.iter()
45+
.flat_map(|it| WalkDir::new(src_dir.join(it)))
46+
.filter_map(|e| e.ok())
47+
.filter(|entry| {
48+
// Get all `.md ` files
49+
entry.file_type().is_file() && entry.path().extension().unwrap_or_default() == "md"
50+
})
51+
.map(|entry| {
52+
let path = entry.path();
53+
let feature_ident = path.file_stem().unwrap().to_str().unwrap().replace("-", "_");
54+
let doc = fs2::read_to_string(path).unwrap();
55+
56+
quote! { LintCompletion { label: #feature_ident, description: #doc } }
57+
});
58+
59+
let ts = quote! {
60+
pub(super) const FEATURES: &[LintCompletion] = &[
61+
#(#definitions),*
62+
];
63+
};
64+
65+
Ok(ts)
66+
}
67+
68+
#[derive(Deserialize)]
69+
struct ClippyLint {
70+
docs: HashMap<String, String>,
71+
id: String,
72+
}
73+
74+
fn generate_descriptor_clippy(uri: &str) -> Result<proc_macro2::TokenStream> {
75+
let file = File::open(uri)?;
76+
let clippy_lints: Vec<ClippyLint> = serde_json::from_reader(file)?;
77+
let definitions = clippy_lints.into_iter().map(|mut clippy_lint| {
78+
let lint_ident = format!("clippy::{}", clippy_lint.id);
79+
let doc = clippy_lint.docs.remove("What it does").unwrap_or_default();
80+
81+
quote! { LintCompletion { label: #lint_ident, description: #doc } }
82+
});
83+
84+
let ts = quote! {
85+
pub(super) const CLIPPY_LINTS: &[LintCompletion] = &[
86+
#(#definitions),*
87+
];
88+
};
89+
90+
Ok(ts)
91+
}

xtask/tests/tidy.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ https://github.blog/2015-06-08-how-to-undo-almost-anything-with-git/#redo-after-
9494
}
9595

9696
fn deny_clippy(path: &PathBuf, text: &String) {
97+
let ignore = &[
98+
// The documentation in string literals may contain anything for its own purposes
99+
"completion/generated_lint_completions.rs",
100+
];
101+
if ignore.iter().any(|p| path.ends_with(p)) {
102+
return;
103+
}
104+
97105
if text.contains("[\u{61}llow(clippy") {
98106
panic!(
99107
"\n\nallowing lints is forbidden: {}.
@@ -109,11 +117,11 @@ See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.
109117

110118
#[test]
111119
fn check_licenses() {
112-
let expected = "
120+
let mut expected = "
113121
0BSD OR MIT OR Apache-2.0
114122
Apache-2.0
115-
Apache-2.0 OR BSL-1.0
116123
Apache-2.0 OR MIT
124+
Apache-2.0 OR BSL-1.0
117125
Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
118126
Apache-2.0/MIT
119127
BSD-2-Clause
@@ -142,6 +150,7 @@ Zlib OR Apache-2.0 OR MIT
142150
.collect::<Vec<_>>();
143151
licenses.sort();
144152
licenses.dedup();
153+
expected.sort();
145154
assert_eq!(licenses, expected);
146155
}
147156

@@ -158,7 +167,7 @@ fn check_todo(path: &Path, text: &str) {
158167
// `ast::make`.
159168
"ast/make.rs",
160169
// The documentation in string literals may contain anything for its own purposes
161-
"completion/generated_features.rs",
170+
"completion/generated_lint_completions.rs",
162171
];
163172
if need_todo.iter().any(|p| path.ends_with(p)) {
164173
return;

0 commit comments

Comments
 (0)