Skip to content

Commit fb83f77

Browse files
arpity22obi1kenobi
andauthored
Add lint inherent_associated_pub_const_missing (#714)
* Added lint inherent_associated_pub_const_missing * fixes * Modifications * Modifications * Adding new test cases * editing test output * Adding new test cases * Adding new test cases * Update src/lints/inherent_associated_pub_const_missing.ron Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> * adding test case * adding test case * Update src/lints/inherent_associated_pub_const_missing.ron Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com> * Query Modifications * Formatting * Apply suggestions from code review --------- Co-authored-by: Predrag Gruevski <2348618+obi1kenobi@users.noreply.github.com>
1 parent 2f235c7 commit fb83f77

8 files changed

Lines changed: 317 additions & 0 deletions

File tree

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
SemverQuery(
2+
id: "inherent_associated_pub_const_missing",
3+
human_readable_name: "inherent impl's associated pub const removed",
4+
description: "An inherent impl's associated public const removed or renamed",
5+
required_update: Major,
6+
reference_link: Some("https://doc.rust-lang.org/cargo/reference/semver.html#item-remove"),
7+
query: r#"
8+
{
9+
CrateDiff {
10+
baseline {
11+
item {
12+
... on ImplOwner {
13+
visibility_limit @filter(op: "=", value: ["$public"]) @output
14+
15+
importable_path {
16+
path @output @tag
17+
public_api @filter(op: "=", value: ["$true"])
18+
}
19+
20+
inherent_impl {
21+
public_api_eligible @filter(op: "=", value: ["$true"])
22+
23+
associated_constant {
24+
associated_constant: name @output @tag
25+
public_api_eligible @filter(op: "=", value: ["$true"])
26+
27+
span_: span @optional {
28+
filename @output
29+
begin_line @output
30+
}
31+
}
32+
}
33+
}
34+
}
35+
}
36+
current {
37+
item {
38+
... on ImplOwner {
39+
visibility_limit @filter(op: "=", value: ["$public"])
40+
name @output
41+
42+
importable_path {
43+
path @filter(op: "=", value: ["%path"])
44+
public_api @filter(op: "=", value: ["$true"])
45+
}
46+
47+
inherent_impl @fold @transform(op: "count") @filter(op: "=", value: ["$zero"]) {
48+
associated_constant {
49+
name @filter(op: "=", value: ["%associated_constant"])
50+
}
51+
}
52+
53+
impl @fold @transform(op: "count") @filter(op: "=", value: ["$zero"]) {
54+
implemented_trait {
55+
trait {
56+
associated_constant {
57+
name @filter(op: "=", value: ["%associated_constant"])
58+
}
59+
}
60+
}
61+
}
62+
}
63+
}
64+
}
65+
}
66+
}"#,
67+
arguments: {
68+
"public": "public",
69+
"true": true,
70+
"zero": 0,
71+
},
72+
error_message: "An inherent impl's associated public constant is removed or renamed",
73+
per_result_error_template: Some("{{name}}::{{associated_constant}}, previously at {{span_filename}}:{{span_begin_line}}"),
74+
)

src/query.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ add_lints!(
506506
function_now_doc_hidden,
507507
function_parameter_count_changed,
508508
function_unsafe_added,
509+
inherent_associated_pub_const_missing,
509510
inherent_method_const_removed,
510511
inherent_method_missing,
511512
inherent_method_must_use_added,
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
publish = false
3+
name = "inherent_associated_pub_const_missing"
4+
version = "0.1.0"
5+
edition = "2021"
6+
7+
[dependencies]
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Test Cases where #[doc(hidden)] is neither added or removed
2+
pub struct StructA {}
3+
4+
impl StructA {
5+
pub const PublicConstantB: i32 = 0;
6+
// Should Be caught on renaming
7+
pub const PublicConstantRenamedA: i32 = 0;
8+
}
9+
10+
struct StructB {}
11+
12+
impl StructB {
13+
// Should not be caught since StructB is not pub
14+
pub const PublicConstantRenamedB: i32 = 0;
15+
}
16+
17+
#[doc(hidden)]
18+
pub struct StructC {}
19+
20+
impl StructC {
21+
// Should not be caught on removing or renaming since the struct is #[doc(hidden)]
22+
pub const PublicConstantRenamedC: i32 = 0;
23+
}
24+
25+
pub struct StructD {}
26+
27+
#[doc(hidden)]
28+
impl StructD {
29+
pub const PublicConstantE: i32 = 0;
30+
}
31+
32+
// Test Cases where #[doc(hidden)] is added
33+
pub struct StructE {}
34+
35+
#[doc(hidden)]
36+
impl StructE {
37+
pub const PublicConstantH: i32 = 0;
38+
}
39+
40+
#[doc(hidden)]
41+
pub struct StructF {}
42+
43+
impl StructF {
44+
pub const PublicConstantJ: i32 = 0;
45+
}
46+
47+
// Test cases where #[doc(hidden)] is removed
48+
pub struct DocHiddenStruct {}
49+
50+
impl DocHiddenStruct {
51+
pub const PublicConstantL: i32 = 0;
52+
}
53+
54+
impl DocHiddenStruct {
55+
pub const PublicConstantO: i32 = 0;
56+
}
57+
58+
// Test for when an inherent const is implemented as trait's const
59+
pub trait TraitA {
60+
const N_A: i64 = 0;
61+
}
62+
63+
pub struct ExampleA;
64+
65+
impl TraitA for ExampleA {}
66+
67+
// Test for when an inherent const is implemented as trait's const but given a value in impl block
68+
pub trait TraitB {
69+
const N_B: i64;
70+
}
71+
72+
pub struct ExampleB;
73+
74+
impl TraitB for ExampleB {
75+
const N_B: i64 = 0;
76+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
publish = false
3+
name = "inherent_associated_pub_const_missing"
4+
version = "0.1.0"
5+
edition = "2021"
6+
7+
[dependencies]
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Test Cases where #[doc(hidden)] is neither added or removed
2+
pub struct StructA {}
3+
4+
impl StructA {
5+
// Basic Test case should be caught
6+
pub const PublicConstantA: i32 = 0;
7+
pub const PublicConstantB: i32 = 0;
8+
// Const that was #[doc(hidden)] will be removed
9+
#[doc(hidden)]
10+
pub const DocHiddenConstantA: i32 = 0;
11+
// Should Be caught on renaming
12+
pub const PublicConstantRenameA: i32 = 0;
13+
// Should not be caught on removing since its not pub
14+
const ConstantA: i32 = 0;
15+
}
16+
17+
struct StructB {}
18+
19+
impl StructB {
20+
// Should not be caught since StructB is not pub
21+
pub const PublicConstantC: i32 = 0;
22+
pub const PublicConstantRenameB: i32 = 0;
23+
const ConstantB: i32 = 0;
24+
}
25+
26+
#[doc(hidden)]
27+
pub struct StructC {}
28+
29+
impl StructC {
30+
// Should not be caught on removing or renaming since the struct #[doc(hidden)]
31+
pub const PublicConstantD: i32 = 0;
32+
pub const PublicConstantRenameC: i32 = 0;
33+
}
34+
35+
pub struct StructD {}
36+
37+
// The constants in this block shouldn't be flagged as removed,
38+
// since they are `#[doc(hidden)]` as a result of the block itself.
39+
#[doc(hidden)]
40+
impl StructD {
41+
pub const PublicConstantE: i32 = 0;
42+
pub const PublicConstantF: i32 = 0;
43+
}
44+
45+
// Test Cases where #[doc(hidden)] is added
46+
pub struct StructE {}
47+
48+
// This impl block will be #[doc(hidden)]
49+
impl StructE {
50+
pub const PublicConstantH: i32 = 0;
51+
// This will be removed
52+
pub const PublicConstantI: i32 = 0;
53+
}
54+
55+
// This struct will be #[doc(hidden)]
56+
pub struct StructF {}
57+
58+
impl StructF {
59+
pub const PublicConstantJ: i32 = 0;
60+
// This const will be removed
61+
pub const PublicConstantK: i32 = 0;
62+
}
63+
64+
// Test cases where #[doc(hidden)] is removed
65+
#[doc(hidden)]
66+
pub struct DocHiddenStruct {}
67+
68+
impl DocHiddenStruct {
69+
// This const will be removed
70+
#[doc(hidden)]
71+
pub const DocHiddenConstantB: i32 = 0;
72+
pub const PublicConstantL: i32 = 0;
73+
// This const will be removed
74+
pub const PublicConstantM: i32 = 0;
75+
}
76+
77+
#[doc(hidden)]
78+
impl DocHiddenStruct {
79+
// This const will be removed
80+
pub const PublicConstantN: i32 = 0;
81+
pub const PublicConstantO: i32 = 0;
82+
}
83+
84+
// Test for when an inherent const is implemented as trait's const
85+
pub trait TraitA {}
86+
87+
pub struct ExampleA;
88+
89+
impl ExampleA {
90+
pub const N_A: i64 = 0;
91+
}
92+
93+
impl TraitA for ExampleA {}
94+
95+
// Test for when an inherent const is implemented as trait's const but given a value in impl
96+
pub trait TraitB {}
97+
98+
pub struct ExampleB;
99+
100+
impl ExampleB {
101+
pub const N_B: i64 = 0;
102+
}
103+
104+
impl TraitB for ExampleB {}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"./test_crates/inherent_associated_pub_const_missing/": [
3+
{
4+
"associated_constant": String("PublicConstantA"),
5+
"name": String("StructA"),
6+
"path": List([
7+
String("inherent_associated_pub_const_missing"),
8+
String("StructA"),
9+
]),
10+
"span_begin_line": Uint64(6),
11+
"span_filename": String("src/lib.rs"),
12+
"visibility_limit": String("public"),
13+
},
14+
{
15+
"associated_constant": String("PublicConstantRenameA"),
16+
"name": String("StructA"),
17+
"path": List([
18+
String("inherent_associated_pub_const_missing"),
19+
String("StructA"),
20+
]),
21+
"span_begin_line": Uint64(12),
22+
"span_filename": String("src/lib.rs"),
23+
"visibility_limit": String("public"),
24+
},
25+
{
26+
"associated_constant": String("PublicConstantI"),
27+
"name": String("StructE"),
28+
"path": List([
29+
String("inherent_associated_pub_const_missing"),
30+
String("StructE"),
31+
]),
32+
"span_begin_line": Uint64(52),
33+
"span_filename": String("src/lib.rs"),
34+
"visibility_limit": String("public"),
35+
},
36+
],
37+
}

test_outputs/struct_now_doc_hidden.output.ron

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,15 @@
11
{
2+
"./test_crates/inherent_associated_pub_const_missing/": [
3+
{
4+
"path": List([
5+
String("inherent_associated_pub_const_missing"),
6+
String("StructF"),
7+
]),
8+
"span_begin_line": Uint64(41),
9+
"span_filename": String("src/lib.rs"),
10+
"struct_name": String("StructF"),
11+
},
12+
],
213
"./test_crates/struct_now_doc_hidden/": [
314
{
415
"path": List([

0 commit comments

Comments
 (0)