mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Support associated types in must_root lint (#34163)
* Support associated types in must_root lint Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fix Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fixups Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fixup Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * Fix crown violations Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fix eng Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * make new test use RUSTC_BOOTSTRAP=1 Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
parent
2d3b46670f
commit
6c2b840e37
7 changed files with 144 additions and 21 deletions
|
@ -55,6 +55,7 @@ pub trait Castable: IDLInterface + DomObject + Sized {
|
|||
|
||||
#[allow(missing_docs)]
|
||||
pub trait HasParent {
|
||||
#[crown::unrooted_must_root_lint::must_root]
|
||||
type Parent;
|
||||
fn as_parent(&self) -> &Self::Parent;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ use crate::script_runtime::{CanGc, JSContext};
|
|||
|
||||
pub trait PermissionAlgorithm {
|
||||
type Descriptor;
|
||||
#[crown::unrooted_must_root_lint::must_root]
|
||||
type Status;
|
||||
fn create_descriptor(
|
||||
cx: JSContext,
|
||||
|
|
|
@ -15,6 +15,7 @@ pub trait WebGLExtension: Sized
|
|||
where
|
||||
Self::Extension: DomObject + JSTraceable,
|
||||
{
|
||||
#[crown::unrooted_must_root_lint::must_root]
|
||||
type Extension;
|
||||
|
||||
/// Creates the DOM object of the WebGL extension.
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use rustc_ast::ast::{AttrKind, Attribute};
|
||||
use rustc_hir::{self as hir, intravisit as visit, ExprKind};
|
||||
use rustc_lint::{LateContext, LateLintPass, LintContext, LintPass, LintStore};
|
||||
use rustc_middle::ty;
|
||||
|
@ -52,19 +51,6 @@ impl UnrootedPass {
|
|||
}
|
||||
}
|
||||
|
||||
fn has_lint_attr(sym: &Symbols, attrs: &[Attribute], name: Symbol) -> bool {
|
||||
attrs.iter().any(|attr| {
|
||||
matches!(
|
||||
&attr.kind,
|
||||
AttrKind::Normal(normal)
|
||||
if normal.item.path.segments.len() == 3 &&
|
||||
normal.item.path.segments[0].ident.name == sym.crown &&
|
||||
normal.item.path.segments[1].ident.name == sym.unrooted_must_root_lint &&
|
||||
normal.item.path.segments[2].ident.name == name
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks if a type is unrooted or contains any owned unrooted types
|
||||
fn is_unrooted_ty<'tcx>(
|
||||
sym: &'_ Symbols,
|
||||
|
@ -82,10 +68,12 @@ fn is_unrooted_ty<'tcx>(
|
|||
continue;
|
||||
},
|
||||
};
|
||||
let has_attr = |did, name| {
|
||||
cx.tcx
|
||||
.has_attrs_with_path(did, &[sym.crown, sym.unrooted_must_root_lint, name])
|
||||
};
|
||||
let recur_into_subtree = match t.kind() {
|
||||
ty::Adt(did, substs) => {
|
||||
let has_attr =
|
||||
|did, name| has_lint_attr(sym, cx.tcx.get_attrs_unchecked(did), name);
|
||||
if has_attr(did.did(), sym.must_root) {
|
||||
ret = true;
|
||||
false
|
||||
|
@ -159,7 +147,17 @@ fn is_unrooted_ty<'tcx>(
|
|||
ty::Ref(..) => false, // don't recurse down &ptrs
|
||||
ty::RawPtr(..) => false, // don't recurse down *ptrs
|
||||
ty::FnDef(..) | ty::FnPtr(_) => false,
|
||||
|
||||
ty::Alias(
|
||||
ty::AliasTyKind::Projection | ty::AliasTyKind::Inherent | ty::AliasTyKind::Weak,
|
||||
ty,
|
||||
) => {
|
||||
if has_attr(ty.def_id, sym.must_root) {
|
||||
ret = true;
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
},
|
||||
_ => true,
|
||||
};
|
||||
if !recur_into_subtree {
|
||||
|
@ -179,8 +177,11 @@ impl<'tcx> LateLintPass<'tcx> for UnrootedPass {
|
|||
/// All structs containing #[crown::unrooted_must_root_lint::must_root] types
|
||||
/// must be #[crown::unrooted_must_root_lint::must_root] themselves
|
||||
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item) {
|
||||
let attrs = cx.tcx.hir().attrs(item.hir_id());
|
||||
if has_lint_attr(&self.symbols, attrs, self.symbols.must_root) {
|
||||
let sym = &self.symbols;
|
||||
if cx.tcx.has_attrs_with_path(
|
||||
item.hir_id().expect_owner(),
|
||||
&[sym.crown, sym.unrooted_must_root_lint, sym.must_root],
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if let hir::ItemKind::Struct(def, ..) = &item.kind {
|
||||
|
@ -204,8 +205,11 @@ impl<'tcx> LateLintPass<'tcx> for UnrootedPass {
|
|||
fn check_variant(&mut self, cx: &LateContext, var: &hir::Variant) {
|
||||
let map = &cx.tcx.hir();
|
||||
let parent_item = map.expect_item(map.get_parent_item(var.hir_id).def_id);
|
||||
let attrs = cx.tcx.hir().attrs(parent_item.hir_id());
|
||||
if !has_lint_attr(&self.symbols, attrs, self.symbols.must_root) {
|
||||
let sym = &self.symbols;
|
||||
if !cx.tcx.has_attrs_with_path(
|
||||
parent_item.hir_id().expect_owner(),
|
||||
&[sym.crown, sym.unrooted_must_root_lint, sym.must_root],
|
||||
) {
|
||||
match var.data {
|
||||
hir::VariantData::Tuple(fields, ..) => {
|
||||
for field in fields {
|
||||
|
@ -226,6 +230,53 @@ impl<'tcx> LateLintPass<'tcx> for UnrootedPass {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// for trait_type_impl_must_root test
|
||||
fn check_trait_item(
|
||||
&mut self,
|
||||
cx: &LateContext<'tcx>,
|
||||
trait_item: &'tcx rustc_hir::TraitItem<'tcx>,
|
||||
) {
|
||||
let hir::TraitItemKind::Type(_, _) = trait_item.kind else {
|
||||
return;
|
||||
};
|
||||
|
||||
let sym = &self.symbols;
|
||||
if cx.tcx.has_attrs_with_path(
|
||||
trait_item.hir_id().expect_owner(),
|
||||
&[sym.crown, sym.unrooted_must_root_lint, sym.must_root],
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
let trait_id = cx
|
||||
.tcx
|
||||
.trait_of_item(trait_item.hir_id().expect_owner().to_def_id())
|
||||
.unwrap();
|
||||
// we need to make sure that all impl do not have any must_root type binded
|
||||
let impls = cx.tcx.trait_impls_of(trait_id);
|
||||
for (_ty, impl_def_ids) in impls.non_blanket_impls() {
|
||||
for impl_def_id in impl_def_ids {
|
||||
let type_impl = cx
|
||||
.tcx
|
||||
.associated_items(impl_def_id)
|
||||
.find_by_name_and_kind(cx.tcx, trait_item.ident, ty::AssocKind::Type, trait_id)
|
||||
.unwrap();
|
||||
let mir_ty = cx.tcx.type_of(type_impl.def_id).skip_binder();
|
||||
if is_unrooted_ty(&self.symbols, cx, mir_ty, false) {
|
||||
cx.lint(UNROOTED_MUST_ROOT, |lint| {
|
||||
lint.primary_message(
|
||||
"Type trait declaration must be marked with \
|
||||
#[crown::unrooted_must_root_lint::must_root] \
|
||||
to allow binding must_root types in associated types",
|
||||
);
|
||||
lint.span(trait_item.span);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Function arguments that are #[crown::unrooted_must_root_lint::must_root] types are not allowed
|
||||
fn check_fn(
|
||||
&mut self,
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
//@rustc-env:RUSTC_BOOTSTRAP=1
|
||||
|
||||
#[crown::unrooted_must_root_lint::must_root]
|
||||
struct Foo;
|
||||
|
||||
trait Trait {
|
||||
type F;
|
||||
//~^ ERROR: Type trait declaration must be marked with #[crown::unrooted_must_root_lint::must_root] to allow binding must_root types in associated types
|
||||
}
|
||||
|
||||
struct TypeHolder;
|
||||
|
||||
impl Trait for TypeHolder {
|
||||
// type F in trait must be also marked as must_root if we want to do this
|
||||
type F = Foo;
|
||||
}
|
||||
|
||||
fn main() {}
|
|
@ -0,0 +1,22 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
//@rustc-env:RUSTC_BOOTSTRAP=1
|
||||
|
||||
struct Foo(i32);
|
||||
|
||||
struct Bar<TH: TypeHolderTrait>(TH::F);
|
||||
//~^ ERROR: Type must be rooted, use #[crown::unrooted_must_root_lint::must_root] on the struct definition to propagate
|
||||
|
||||
trait TypeHolderTrait {
|
||||
#[crown::unrooted_must_root_lint::must_root]
|
||||
type F;
|
||||
}
|
||||
|
||||
struct TypeHolder;
|
||||
|
||||
impl TypeHolderTrait for TypeHolder {
|
||||
type F = Foo;
|
||||
}
|
||||
|
||||
fn main() {}
|
26
support/crown/tests/run-pass/type_holder_must_root.rs
Normal file
26
support/crown/tests/run-pass/type_holder_must_root.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
//@rustc-env:RUSTC_BOOTSTRAP=1
|
||||
|
||||
#[crown::unrooted_must_root_lint::must_root]
|
||||
struct Foo(i32);
|
||||
#[crown::unrooted_must_root_lint::must_root]
|
||||
struct Bar<TH: TypeHolderTrait>(TH::F, TH::B);
|
||||
|
||||
struct Baz(i32);
|
||||
|
||||
trait TypeHolderTrait {
|
||||
#[crown::unrooted_must_root_lint::must_root]
|
||||
type F;
|
||||
type B;
|
||||
}
|
||||
|
||||
struct TypeHolder;
|
||||
|
||||
impl TypeHolderTrait for TypeHolder {
|
||||
type F = Foo;
|
||||
type B = Baz;
|
||||
}
|
||||
|
||||
fn main() {}
|
Loading…
Add table
Add a link
Reference in a new issue