Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Private-in-public lints implementation #111801

Merged
merged 1 commit into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3372,7 +3372,9 @@ declare_lint_pass! {
OVERLAPPING_RANGE_ENDPOINTS,
PATTERNS_IN_FNS_WITHOUT_BODY,
POINTER_STRUCTURAL_MATCH,
PRIVATE_BOUNDS,
PRIVATE_IN_PUBLIC,
PRIVATE_INTERFACES,
PROC_MACRO_BACK_COMPAT,
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
Expand All @@ -3399,6 +3401,7 @@ declare_lint_pass! {
UNINHABITED_STATIC,
UNKNOWN_CRATE_TYPES,
UNKNOWN_LINTS,
UNNAMEABLE_TYPES,
UNREACHABLE_CODE,
UNREACHABLE_PATTERNS,
UNSAFE_OP_IN_UNSAFE_FN,
Expand Down Expand Up @@ -4251,3 +4254,95 @@ declare_lint! {
Warn,
"\"invalid_parameter\" isn't a valid argument for `#[macro_export]`",
}

declare_lint! {
/// The `private_interfaces` lint detects types in a primary interface of an item,
/// that are more private than the item itself. Primary interface of an item is all
/// its interface except for bounds on generic parameters and where clauses.
///
/// ### Example
///
/// ```rust,compile_fail
/// # #![allow(unused)]
/// # #![allow(private_in_public)]
/// #![deny(private_interfaces)]
/// struct SemiPriv;
///
/// mod m1 {
/// struct Priv;
/// impl crate::SemiPriv {
/// pub fn f(_: Priv) {}
/// }
/// }
///
/// # fn main() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Having something private in primary interface guarantees that
/// the item will be unusable from outer modules due to type privacy.
pub PRIVATE_INTERFACES,
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
Allow,
"private type in primary interface of an item",
}

declare_lint! {
/// The `private_bounds` lint detects types in a secondary interface of an item,
/// that are more private than the item itself. Secondary interface of an item consists of
/// bounds on generic parameters and where clauses, including supertraits for trait items.
///
/// ### Example
///
/// ```rust,compile_fail
/// # #![allow(private_in_public)]
/// # #![allow(unused)]
/// #![deny(private_bounds)]
///
/// struct PrivTy;
/// pub struct S
/// where PrivTy:
/// {}
/// # fn main() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// Having private types or traits in item bounds makes it less clear what interface
/// the item actually provides.
pub PRIVATE_BOUNDS,
Allow,
"private type in secondary interface of an item"
}

declare_lint! {
/// The `unnameable_types` lint detects types for which you can get objects of that type,
/// but cannot name the type itself.
///
/// ### Example
///
/// ```rust,compile_fail
/// # #![allow(unused)]
/// #![deny(unnameable_types)]
/// mod m {
/// pub struct S;
/// }
///
/// pub fn get_voldemort() -> m::S { m::S }
/// # fn main() {}
/// ```
///
/// {{produces}}
///
/// ### Explanation
///
/// It is often expected that if you can obtain an object of type `T`, then
/// you can name the type `T` as well, this lint attempts to enforce this rule.
pub UNNAMEABLE_TYPES,
Allow,
"effective visibility of a type is larger than the area in which it can be named"
}
7 changes: 7 additions & 0 deletions compiler/rustc_privacy/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ privacy_private_in_public_lint =
*[other] E0446
})

privacy_private_interface_or_bounds_lint = {$ty_kind} `{$ty_descr}` is more private than the item `{$item_descr}`
.item_note = {$item_kind} `{$item_descr}` is reachable at visibility `{$item_vis_descr}`
.ty_note = but {$ty_kind} `{$ty_descr}` is only usable at visibility `{$ty_vis_descr}`

privacy_report_effective_visibility = {$descr}

privacy_unnameable_types_lint = {$kind} `{$descr}` is reachable but cannot be named
.label = reachable at visibility `{$reachable_vis}`, but can only be named at visibility `{$reexported_vis}`

privacy_unnamed_item_is_private = {$kind} is private
.label = private {$kind}
29 changes: 29 additions & 0 deletions compiler/rustc_privacy/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,32 @@ pub struct PrivateInPublicLint<'a> {
pub kind: &'a str,
pub descr: DiagnosticArgFromDisplay<'a>,
}

#[derive(LintDiagnostic)]
#[diag(privacy_unnameable_types_lint)]
pub struct UnnameableTypesLint<'a> {
#[label]
pub span: Span,
pub kind: &'a str,
pub descr: DiagnosticArgFromDisplay<'a>,
pub reachable_vis: &'a str,
pub reexported_vis: &'a str,
}

// Used for `private_interfaces` and `private_bounds` lints.
// They will replace private-in-public errors and compatibility lints in future.
// See https://rust-lang.github.io/rfcs/2145-type-privacy.html for more details.
#[derive(LintDiagnostic)]
#[diag(privacy_private_interface_or_bounds_lint)]
pub struct PrivateInterfacesOrBoundsLint<'a> {
#[note(privacy_item_note)]
pub item_span: Span,
pub item_kind: &'a str,
pub item_descr: DiagnosticArgFromDisplay<'a>,
pub item_vis_descr: &'a str,
#[note(privacy_ty_note)]
pub ty_span: Span,
pub ty_kind: &'a str,
pub ty_descr: DiagnosticArgFromDisplay<'a>,
pub ty_vis_descr: &'a str,
}
Loading