aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJade <[email protected]>2021-04-08 12:37:34 +0100
committerJade <[email protected]>2021-04-08 22:43:19 +0100
commit4529f1be81b3b1424447908f2446776f44748fcd (patch)
tree156a62b6a97c93c987ddd6609ab4ec5a690c0c1b
parent855a739ebf736db8a9a66e0e073c34631275fb22 (diff)
decl_check: consider outer scopes' allows
Fix #8417. Also makes it less noisy about no_mangle annotated stuff the user can do nothing about. Note: this still is broken with bitfield! macros. A repro in an ignore test is included here. I believe this bug is elsewhere, and I don't think I can work around it here.
-rw-r--r--crates/hir_def/src/lib.rs10
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs132
-rw-r--r--docs/user/manual.adoc2
3 files changed, 133 insertions, 11 deletions
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index e2af0e514..eefc75706 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -435,6 +435,16 @@ impl_from!(
435 for AttrDefId 435 for AttrDefId
436); 436);
437 437
438impl From<AssocContainerId> for AttrDefId {
439 fn from(acid: AssocContainerId) -> Self {
440 match acid {
441 AssocContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
442 AssocContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
443 AssocContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
444 }
445 }
446}
447
438#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 448#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
439pub enum VariantId { 449pub enum VariantId {
440 EnumVariantId(EnumVariantId), 450 EnumVariantId(EnumVariantId),
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 1c9f9ede7..31532f327 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -35,6 +35,8 @@ use crate::{
35}; 35};
36 36
37mod allow { 37mod allow {
38 pub(super) const BAD_STYLE: &str = "bad_style";
39 pub(super) const NONSTANDARD_STYLE: &str = "nonstandard_style";
38 pub(super) const NON_SNAKE_CASE: &str = "non_snake_case"; 40 pub(super) const NON_SNAKE_CASE: &str = "non_snake_case";
39 pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals"; 41 pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals";
40 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; 42 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
@@ -83,10 +85,39 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
83 } 85 }
84 86
85 /// Checks whether not following the convention is allowed for this item. 87 /// Checks whether not following the convention is allowed for this item.
86 /// 88 fn allowed(&self, id: AttrDefId, allow_name: &str, recursing: bool) -> bool {
87 /// Currently this method doesn't check parent attributes. 89 let is_allowed = |def_id| {
88 fn allowed(&self, id: AttrDefId, allow_name: &str) -> bool { 90 let attrs = self.db.attrs(def_id);
89 self.db.attrs(id).by_key("allow").tt_values().any(|tt| tt.to_string().contains(allow_name)) 91 // don't bug the user about directly no_mangle annotated stuff, they can't do anything about it
92 (!recursing && attrs.by_key("no_mangle").exists())
93 || attrs.by_key("allow").tt_values().any(|tt| {
94 let allows = tt.to_string();
95 allows.contains(allow_name)
96 || allows.contains(allow::BAD_STYLE)
97 || allows.contains(allow::NONSTANDARD_STYLE)
98 })
99 };
100
101 is_allowed(id)
102 // go upwards one step or give up
103 || match id {
104 AttrDefId::ModuleId(m) => m.containing_module(self.db.upcast()).map(|v| v.into()),
105 AttrDefId::FunctionId(f) => Some(f.lookup(self.db.upcast()).container.into()),
106 AttrDefId::StaticId(sid) => Some(sid.lookup(self.db.upcast()).container.into()),
107 AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()),
108 AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()),
109 AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()),
110 // These warnings should not explore macro definitions at all
111 AttrDefId::MacroDefId(_) => None,
112 // Will never occur under an enum/struct/union/type alias
113 AttrDefId::AdtId(_) => None,
114 AttrDefId::FieldId(_) => None,
115 AttrDefId::EnumVariantId(_) => None,
116 AttrDefId::TypeAliasId(_) => None,
117 AttrDefId::GenericParamId(_) => None,
118 }
119 .map(|mid| self.allowed(mid, allow_name, true))
120 .unwrap_or(false)
90 } 121 }
91 122
92 fn validate_func(&mut self, func: FunctionId) { 123 fn validate_func(&mut self, func: FunctionId) {
@@ -109,7 +140,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
109 } 140 }
110 141
111 // Check whether non-snake case identifiers are allowed for this function. 142 // Check whether non-snake case identifiers are allowed for this function.
112 if self.allowed(func.into(), allow::NON_SNAKE_CASE) { 143 if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) {
113 return; 144 return;
114 } 145 }
115 146
@@ -328,8 +359,9 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
328 fn validate_struct(&mut self, struct_id: StructId) { 359 fn validate_struct(&mut self, struct_id: StructId) {
329 let data = self.db.struct_data(struct_id); 360 let data = self.db.struct_data(struct_id);
330 361
331 let non_camel_case_allowed = self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES); 362 let non_camel_case_allowed =
332 let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE); 363 self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES, false);
364 let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE, false);
333 365
334 // Check the structure name. 366 // Check the structure name.
335 let struct_name = data.name.to_string(); 367 let struct_name = data.name.to_string();
@@ -461,7 +493,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
461 let data = self.db.enum_data(enum_id); 493 let data = self.db.enum_data(enum_id);
462 494
463 // Check whether non-camel case names are allowed for this enum. 495 // Check whether non-camel case names are allowed for this enum.
464 if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES) { 496 if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
465 return; 497 return;
466 } 498 }
467 499
@@ -584,7 +616,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
584 fn validate_const(&mut self, const_id: ConstId) { 616 fn validate_const(&mut self, const_id: ConstId) {
585 let data = self.db.const_data(const_id); 617 let data = self.db.const_data(const_id);
586 618
587 if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL) { 619 if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
588 return; 620 return;
589 } 621 }
590 622
@@ -632,7 +664,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
632 return; 664 return;
633 } 665 }
634 666
635 if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL) { 667 if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
636 return; 668 return;
637 } 669 }
638 670
@@ -869,10 +901,36 @@ fn main() {
869 r#" 901 r#"
870 #[allow(non_snake_case)] 902 #[allow(non_snake_case)]
871 fn NonSnakeCaseName(SOME_VAR: u8) -> u8{ 903 fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
904 // cov_flags generated output from elsewhere in this file
905 extern "C" {
906 #[no_mangle]
907 static lower_case: u8;
908 }
909
872 let OtherVar = SOME_VAR + 1; 910 let OtherVar = SOME_VAR + 1;
873 OtherVar 911 OtherVar
874 } 912 }
875 913
914 #[allow(nonstandard_style)]
915 mod CheckNonstandardStyle {
916 fn HiImABadFnName() {}
917 }
918
919 #[allow(bad_style)]
920 mod CheckBadStyle {
921 fn HiImABadFnName() {}
922 }
923
924 mod F {
925 #![allow(non_snake_case)]
926 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
927 }
928
929 trait BAD_TRAIT {
930 fn BAD_FUNCTION();
931 fn BadFunction();
932 }
933
876 #[allow(non_snake_case, non_camel_case_types)] 934 #[allow(non_snake_case, non_camel_case_types)]
877 pub struct some_type { 935 pub struct some_type {
878 SOME_FIELD: u8, 936 SOME_FIELD: u8,
@@ -889,6 +947,60 @@ fn main() {
889 } 947 }
890 948
891 #[test] 949 #[test]
950 fn allow_attributes_crate_attr() {
951 check_diagnostics(
952 r#"
953 #![allow(non_snake_case)]
954
955 mod F {
956 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
957 }
958
959 "#,
960 );
961 }
962
963 #[test]
964 #[ignore]
965 fn bug_trait_inside_fn() {
966 // FIXME:
967 // This is broken, and in fact, should not even be looked at by this
968 // lint in the first place. There's weird stuff going on in the
969 // collection phase.
970 // It's currently being brought in by:
971 // * validate_func on `a` recursing into modules
972 // * then it finds the trait and then the function while iterating
973 // through modules
974 // * then validate_func is called on Dirty
975 // * ... which then proceeds to look at some unknown module taking no
976 // attrs from either the impl or the fn a, and then finally to the root
977 // module
978 //
979 // It should find the attribute on the trait, but it *doesn't even see
980 // the trait* as far as I can tell.
981
982 check_diagnostics(
983 r#"
984trait T { fn a(); }
985struct U {}
986impl T for U {
987 fn a() {
988 // this comes out of bitflags, mostly
989 #[allow(non_snake_case)]
990 trait __BitFlags {
991 const HiImAlsoBad: u8 = 2;
992 #[inline]
993 fn Dirty(&self) -> bool {
994 false
995 }
996 }
997
998 }
999}"#,
1000 );
1001 }
1002
1003 #[test]
892 fn ignores_extern_items() { 1004 fn ignores_extern_items() {
893 cov_mark::check!(extern_func_incorrect_case_ignored); 1005 cov_mark::check!(extern_func_incorrect_case_ignored);
894 cov_mark::check!(extern_static_incorrect_case_ignored); 1006 cov_mark::check!(extern_static_incorrect_case_ignored);
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index e74b287fb..b86e91772 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -541,7 +541,7 @@ include::./generated_assists.adoc[]
541== Diagnostics 541== Diagnostics
542 542
543While most errors and warnings provided by rust-analyzer come from the `cargo check` integration, there's a growing number of diagnostics implemented using rust-analyzer's own analysis. 543While most errors and warnings provided by rust-analyzer come from the `cargo check` integration, there's a growing number of diagnostics implemented using rust-analyzer's own analysis.
544These diagnostics don't respect `#[allow]` or `#[deny]` attributes yet, but can be turned off using the `rust-analyzer.diagnostics.enable`, `rust-analyzer.diagnostics.enableExperimental` or `rust-analyzer.diagnostics.disabled` settings. 544Some of these diagnostics don't respect `\#[allow]` or `\#[deny]` attributes yet, but can be turned off using the `rust-analyzer.diagnostics.enable`, `rust-analyzer.diagnostics.enableExperimental` or `rust-analyzer.diagnostics.disabled` settings.
545 545
546include::./generated_diagnostic.adoc[] 546include::./generated_diagnostic.adoc[]
547 547