Skip to content

Commit 0d1dc51

Browse files
authored
Implement more checks in cargo-check-external-types (#1645)
Adds support for unions, and marks unstable Rust language features as unsupported.
1 parent 5b260e5 commit 0d1dc51

File tree

10 files changed

+130
-14
lines changed

10 files changed

+130
-14
lines changed

tools/cargo-check-external-types/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tools/cargo-check-external-types/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "cargo-check-external-types"
3-
version = "0.1.1"
3+
version = "0.1.2"
44
authors = ["AWS Rust SDK Team <[email protected]>", "John DiSanti <[email protected]>"]
55
description = "Static analysis tool to detect external types exposed in a library's public API."
66
edition = "2021"

tools/cargo-check-external-types/src/path.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub enum ComponentType {
2424
StructField,
2525
Trait,
2626
TypeDef,
27+
Union,
2728
}
2829

2930
/// Represents one component in a [`Path`].

tools/cargo-check-external-types/src/visitor.rs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,23 @@ use crate::path::{ComponentType, Path};
1010
use anyhow::{anyhow, Context, Result};
1111
use rustdoc_types::{
1212
Crate, FnDecl, GenericArgs, GenericBound, GenericParamDef, GenericParamDefKind, Generics, Id,
13-
Item, ItemEnum, ItemSummary, Struct, Term, Trait, Type, Variant, Visibility, WherePredicate,
13+
Item, ItemEnum, ItemSummary, Struct, Term, Trait, Type, Union, Variant, Visibility,
14+
WherePredicate,
1415
};
1516
use std::cell::RefCell;
1617
use std::collections::{BTreeSet, HashMap};
1718
use tracing::debug;
1819
use tracing_attributes::instrument;
1920

21+
macro_rules! unstable_rust_feature {
22+
($name:expr, $documentation_uri:expr) => {
23+
panic!(
24+
"unstable Rust feature '{}' (see {}) is not supported by cargo-check-external-types",
25+
$name, $documentation_uri
26+
)
27+
};
28+
}
29+
2030
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2131
enum VisibilityCheck {
2232
/// Check to make sure the item is public before visiting it
@@ -137,7 +147,10 @@ impl Visitor {
137147
self.visit_item(&path, self.item(id)?, VisibilityCheck::Default)?;
138148
}
139149
}
140-
ItemEnum::ForeignType => unimplemented!("visit_item ItemEnum::ForeignType"),
150+
ItemEnum::ForeignType => unstable_rust_feature!(
151+
"extern_types",
152+
"https://doc.rust-lang.org/beta/unstable-book/language-features/extern-types.html"
153+
),
141154
ItemEnum::Function(function) => {
142155
path.push(ComponentType::Function, item);
143156
self.visit_fn_decl(&path, &function.decl)?;
@@ -176,7 +189,7 @@ impl Visitor {
176189
}
177190
}
178191
}
179-
ItemEnum::OpaqueTy(_) => unimplemented!("visit_item ItemEnum::OpaqueTy"),
192+
ItemEnum::OpaqueTy(_) => unstable_rust_feature!("type_alias_impl_trait", "https://doc.rust-lang.org/beta/unstable-book/language-features/type-alias-impl-trait.html"),
180193
ItemEnum::Static(sttc) => {
181194
path.push(ComponentType::Static, item);
182195
self.visit_type(&path, &ErrorLocation::Static, &sttc.type_)?;
@@ -200,10 +213,14 @@ impl Visitor {
200213
.context(here!())?;
201214
self.visit_generics(&path, &typedef.generics)?;
202215
}
203-
// Trait aliases aren't stable:
204-
// https://doc.rust-lang.org/beta/unstable-book/language-features/trait-alias.html
205-
ItemEnum::TraitAlias(_) => unimplemented!("unstable trait alias support"),
206-
ItemEnum::Union(_) => unimplemented!("union support"),
216+
ItemEnum::TraitAlias(_) => unstable_rust_feature!(
217+
"trait_alias",
218+
"https://doc.rust-lang.org/beta/unstable-book/language-features/trait-alias.html"
219+
),
220+
ItemEnum::Union(unn) => {
221+
path.push(ComponentType::Union, item);
222+
self.visit_union(&path, unn)?;
223+
}
207224
ItemEnum::Variant(variant) => {
208225
path.push(ComponentType::EnumVariant, item);
209226
self.visit_variant(&path, variant)?;
@@ -230,6 +247,19 @@ impl Visitor {
230247
Ok(())
231248
}
232249

250+
#[instrument(level = "debug", skip(self, path, unn), fields(path = %path))]
251+
fn visit_union(&self, path: &Path, unn: &Union) -> Result<()> {
252+
self.visit_generics(path, &unn.generics)?;
253+
for id in &unn.fields {
254+
let field = self.item(id)?;
255+
self.visit_item(path, field, VisibilityCheck::Default)?;
256+
}
257+
for id in &unn.impls {
258+
self.visit_impl(path, self.item(id)?)?;
259+
}
260+
Ok(())
261+
}
262+
233263
#[instrument(level = "debug", skip(self, path, trt), fields(path = %path))]
234264
fn visit_trait(&self, path: &Path, trt: &Trait) -> Result<()> {
235265
self.visit_generics(path, &trt.generics)?;
@@ -321,7 +351,12 @@ impl Visitor {
321351
}
322352
}
323353
}
324-
Type::Infer => unimplemented!("visit_type Type::Infer"),
354+
Type::Infer => {
355+
unimplemented!(
356+
"visit_type for Type::Infer: not sure what Rust code triggers this. \
357+
If you encounter this, please report it with a link to the code it happens with."
358+
)
359+
}
325360
Type::RawPointer { type_, .. } => {
326361
self.visit_type(path, what, type_).context(here!())?
327362
}

tools/cargo-check-external-types/test-workspace/external-lib/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,10 @@ pub trait AssociatedGenericTrait {
3333
}
3434

3535
pub struct SimpleNewType(pub u32);
36+
37+
#[repr(C)]
38+
#[derive(Copy, Clone)]
39+
pub struct ReprCType {
40+
i: i32,
41+
f: f32,
42+
}

tools/cargo-check-external-types/test-workspace/test-crate/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
//! This crate is used to test the cargo-check-external-types by exercising the all possible
1010
//! exposure of external types in a public API.
1111
12+
pub mod test_union;
13+
1214
use external_lib::{
1315
AssociatedGenericTrait,
1416
SimpleNewType,
@@ -23,8 +25,6 @@ use external_lib::{
2325
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
2426
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
2527
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
26-
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
27-
// Remove this comment if more lines are needed for imports in the future to preserve line numbers
2828
};
2929

3030
pub struct LocalStruct;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
use external_lib::{ReprCType, SimpleTrait};
7+
8+
#[repr(C)]
9+
pub union SimpleUnion {
10+
pub repr_c: ReprCType,
11+
pub something_else: u64,
12+
}
13+
14+
impl SimpleUnion {
15+
pub fn repr_c(&self) -> &ReprCType {
16+
&self.repr_c
17+
}
18+
}
19+
20+
#[repr(C)]
21+
pub union GenericUnion<T: Copy + SimpleTrait> {
22+
pub repr_c: T,
23+
pub something_else: u64,
24+
}

tools/cargo-check-external-types/tests/allow-some-types-expected-output.txt

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,22 @@ error: Unapproved external type `external_lib::AssociatedGenericTrait` reference
1818
|
1919
= in trait bound of `test_crate::SomeTraitWithExternalDefaultTypes::OtherThing`
2020

21-
2 errors emitted
21+
error: Unapproved external type `external_lib::ReprCType` referenced in public API
22+
--> test-crate/src/test_union.rs:10:5
23+
|
24+
10 | pub repr_c: ReprCType,
25+
| ^-------------------^
26+
|
27+
= in struct field of `test_crate::test_union::SimpleUnion::repr_c`
28+
29+
error: Unapproved external type `external_lib::ReprCType` referenced in public API
30+
--> test-crate/src/test_union.rs:15:5
31+
|
32+
15 | pub fn repr_c(&self) -> &ReprCType {
33+
| ...
34+
17 | }␊
35+
| ^
36+
|
37+
= in return value of `test_crate::test_union::SimpleUnion::repr_c`
38+
39+
4 errors emitted

tools/cargo-check-external-types/tests/default-config-expected-output.txt

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,4 +338,32 @@ error: Unapproved external type `external_lib::SimpleNewType` referenced in publ
338338
|
339339
= in struct field of `test_crate::AssocConstStruct::OTHER_CONST`
340340

341-
39 errors emitted
341+
error: Unapproved external type `external_lib::ReprCType` referenced in public API
342+
--> test-crate/src/test_union.rs:10:5
343+
|
344+
10 | pub repr_c: ReprCType,
345+
| ^-------------------^
346+
|
347+
= in struct field of `test_crate::test_union::SimpleUnion::repr_c`
348+
349+
error: Unapproved external type `external_lib::ReprCType` referenced in public API
350+
--> test-crate/src/test_union.rs:15:5
351+
|
352+
15 | pub fn repr_c(&self) -> &ReprCType {
353+
| ...
354+
17 | }␊
355+
| ^
356+
|
357+
= in return value of `test_crate::test_union::SimpleUnion::repr_c`
358+
359+
error: Unapproved external type `external_lib::SimpleTrait` referenced in public API
360+
--> test-crate/src/test_union.rs:21:1
361+
|
362+
21 | pub union GenericUnion<T: Copy + SimpleTrait> {
363+
| ...
364+
24 | }␊
365+
| ^
366+
|
367+
= in trait bound of `test_crate::test_union::GenericUnion`
368+
369+
42 errors emitted

tools/cargo-check-external-types/tests/output-format-markdown-table-expected-output.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
| --- | --- | --- |
33
| external_lib | external_lib::AssociatedGenericTrait | test-crate/src/lib.rs:125:0 |
44
| external_lib | external_lib::AssociatedGenericTrait | test-crate/src/lib.rs:136:4 |
5+
| external_lib | external_lib::ReprCType | test-crate/src/test_union.rs:10:4 |
6+
| external_lib | external_lib::ReprCType | test-crate/src/test_union.rs:15:4 |
57
| external_lib | external_lib::SimpleNewType | test-crate/src/lib.rs:158:4 |
68
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:104:4 |
79
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:122:0 |
@@ -13,6 +15,7 @@
1315
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:47:0 |
1416
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:89:4 |
1517
| external_lib | external_lib::SimpleTrait | test-crate/src/lib.rs:92:8 |
18+
| external_lib | external_lib::SimpleTrait | test-crate/src/test_union.rs:21:0 |
1619
| external_lib | external_lib::SomeOtherStruct | test-crate/src/lib.rs:125:0 |
1720
| external_lib | external_lib::SomeOtherStruct | test-crate/src/lib.rs:136:4 |
1821
| external_lib | external_lib::SomeOtherStruct | test-crate/src/lib.rs:72:4 |

0 commit comments

Comments
 (0)