Unverified Commit 0d1dc51b authored by John DiSanti's avatar John DiSanti Committed by GitHub
Browse files

Implement more checks in `cargo-check-external-types` (#1645)

Adds support for unions, and marks unstable Rust language features as unsupported.
parent 5b260e5d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ dependencies = [

[[package]]
name = "cargo-check-external-types"
version = "0.1.1"
version = "0.1.2"
dependencies = [
 "anyhow",
 "cargo_metadata",
+1 −1
Original line number Diff line number Diff line
[package]
name = "cargo-check-external-types"
version = "0.1.1"
version = "0.1.2"
authors = ["AWS Rust SDK Team <aws-sdk-rust@amazon.com>", "John DiSanti <jdisanti@amazon.com>"]
description = "Static analysis tool to detect external types exposed in a library's public API."
edition = "2021"
+1 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ pub enum ComponentType {
    StructField,
    Trait,
    TypeDef,
    Union,
}

/// Represents one component in a [`Path`].
+43 −8
Original line number Diff line number Diff line
@@ -10,13 +10,23 @@ use crate::path::{ComponentType, Path};
use anyhow::{anyhow, Context, Result};
use rustdoc_types::{
    Crate, FnDecl, GenericArgs, GenericBound, GenericParamDef, GenericParamDefKind, Generics, Id,
    Item, ItemEnum, ItemSummary, Struct, Term, Trait, Type, Variant, Visibility, WherePredicate,
    Item, ItemEnum, ItemSummary, Struct, Term, Trait, Type, Union, Variant, Visibility,
    WherePredicate,
};
use std::cell::RefCell;
use std::collections::{BTreeSet, HashMap};
use tracing::debug;
use tracing_attributes::instrument;

macro_rules! unstable_rust_feature {
    ($name:expr, $documentation_uri:expr) => {
        panic!(
            "unstable Rust feature '{}' (see {}) is not supported by cargo-check-external-types",
            $name, $documentation_uri
        )
    };
}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
enum VisibilityCheck {
    /// Check to make sure the item is public before visiting it
@@ -137,7 +147,10 @@ impl Visitor {
                    self.visit_item(&path, self.item(id)?, VisibilityCheck::Default)?;
                }
            }
            ItemEnum::ForeignType => unimplemented!("visit_item ItemEnum::ForeignType"),
            ItemEnum::ForeignType => unstable_rust_feature!(
                "extern_types",
                "https://doc.rust-lang.org/beta/unstable-book/language-features/extern-types.html"
            ),
            ItemEnum::Function(function) => {
                path.push(ComponentType::Function, item);
                self.visit_fn_decl(&path, &function.decl)?;
@@ -176,7 +189,7 @@ impl Visitor {
                    }
                }
            }
            ItemEnum::OpaqueTy(_) => unimplemented!("visit_item ItemEnum::OpaqueTy"),
            ItemEnum::OpaqueTy(_) => unstable_rust_feature!("type_alias_impl_trait", "https://doc.rust-lang.org/beta/unstable-book/language-features/type-alias-impl-trait.html"),
            ItemEnum::Static(sttc) => {
                path.push(ComponentType::Static, item);
                self.visit_type(&path, &ErrorLocation::Static, &sttc.type_)?;
@@ -200,10 +213,14 @@ impl Visitor {
                    .context(here!())?;
                self.visit_generics(&path, &typedef.generics)?;
            }
            // Trait aliases aren't stable:
            // https://doc.rust-lang.org/beta/unstable-book/language-features/trait-alias.html
            ItemEnum::TraitAlias(_) => unimplemented!("unstable trait alias support"),
            ItemEnum::Union(_) => unimplemented!("union support"),
            ItemEnum::TraitAlias(_) => unstable_rust_feature!(
                "trait_alias",
                "https://doc.rust-lang.org/beta/unstable-book/language-features/trait-alias.html"
            ),
            ItemEnum::Union(unn) => {
                path.push(ComponentType::Union, item);
                self.visit_union(&path, unn)?;
            }
            ItemEnum::Variant(variant) => {
                path.push(ComponentType::EnumVariant, item);
                self.visit_variant(&path, variant)?;
@@ -230,6 +247,19 @@ impl Visitor {
        Ok(())
    }

    #[instrument(level = "debug", skip(self, path, unn), fields(path = %path))]
    fn visit_union(&self, path: &Path, unn: &Union) -> Result<()> {
        self.visit_generics(path, &unn.generics)?;
        for id in &unn.fields {
            let field = self.item(id)?;
            self.visit_item(path, field, VisibilityCheck::Default)?;
        }
        for id in &unn.impls {
            self.visit_impl(path, self.item(id)?)?;
        }
        Ok(())
    }

    #[instrument(level = "debug", skip(self, path, trt), fields(path = %path))]
    fn visit_trait(&self, path: &Path, trt: &Trait) -> Result<()> {
        self.visit_generics(path, &trt.generics)?;
@@ -321,7 +351,12 @@ impl Visitor {
                    }
                }
            }
            Type::Infer => unimplemented!("visit_type Type::Infer"),
            Type::Infer => {
                unimplemented!(
                    "visit_type for Type::Infer: not sure what Rust code triggers this. \
                    If you encounter this, please report it with a link to the code it happens with."
                )
            }
            Type::RawPointer { type_, .. } => {
                self.visit_type(path, what, type_).context(here!())?
            }
+7 −0
Original line number Diff line number Diff line
@@ -33,3 +33,10 @@ pub trait AssociatedGenericTrait {
}

pub struct SimpleNewType(pub u32);

#[repr(C)]
#[derive(Copy, Clone)]
pub struct ReprCType {
    i: i32,
    f: f32,
}
Loading