Auto merge of #17078 - Veykril:diags-perf, r=Veykril
internal: Improve diagnostics performance
This commit is contained in:
commit
90cfa8035f
@ -45,7 +45,7 @@ pub trait Upcast<T: ?Sized> {
|
|||||||
|
|
||||||
pub const DEFAULT_FILE_TEXT_LRU_CAP: usize = 16;
|
pub const DEFAULT_FILE_TEXT_LRU_CAP: usize = 16;
|
||||||
pub const DEFAULT_PARSE_LRU_CAP: usize = 128;
|
pub const DEFAULT_PARSE_LRU_CAP: usize = 128;
|
||||||
pub const DEFAULT_BORROWCK_LRU_CAP: usize = 1024;
|
pub const DEFAULT_BORROWCK_LRU_CAP: usize = 2024;
|
||||||
|
|
||||||
pub trait FileLoader {
|
pub trait FileLoader {
|
||||||
/// Text of the file.
|
/// Text of the file.
|
||||||
|
@ -510,6 +510,7 @@ pub struct ConstData {
|
|||||||
pub type_ref: Interned<TypeRef>,
|
pub type_ref: Interned<TypeRef>,
|
||||||
pub visibility: RawVisibility,
|
pub visibility: RawVisibility,
|
||||||
pub rustc_allow_incoherent_impl: bool,
|
pub rustc_allow_incoherent_impl: bool,
|
||||||
|
pub has_body: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstData {
|
impl ConstData {
|
||||||
@ -533,6 +534,7 @@ pub(crate) fn const_data_query(db: &dyn DefDatabase, konst: ConstId) -> Arc<Cons
|
|||||||
type_ref: konst.type_ref.clone(),
|
type_ref: konst.type_ref.clone(),
|
||||||
visibility,
|
visibility,
|
||||||
rustc_allow_incoherent_impl,
|
rustc_allow_incoherent_impl,
|
||||||
|
has_body: konst.has_body,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
|
tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
|
||||||
type_ref::TypeRef,
|
type_ref::TypeRef,
|
||||||
visibility::RawVisibility,
|
visibility::RawVisibility,
|
||||||
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId,
|
EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Note that we use `StructData` for unions as well!
|
/// Note that we use `StructData` for unions as well!
|
||||||
@ -378,6 +378,15 @@ pub fn kind(&self) -> StructKind {
|
|||||||
VariantData::Unit => StructKind::Unit,
|
VariantData::Unit => StructKind::Unit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::self_named_constructors)]
|
||||||
|
pub(crate) fn variant_data(db: &dyn DefDatabase, id: VariantId) -> Arc<VariantData> {
|
||||||
|
match id {
|
||||||
|
VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
|
||||||
|
VariantId::EnumVariantId(it) => db.enum_variant_data(it).variant_data.clone(),
|
||||||
|
VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
attr::{Attrs, AttrsWithOwner},
|
attr::{Attrs, AttrsWithOwner},
|
||||||
body::{scope::ExprScopes, Body, BodySourceMap},
|
body::{scope::ExprScopes, Body, BodySourceMap},
|
||||||
data::{
|
data::{
|
||||||
adt::{EnumData, EnumVariantData, StructData},
|
adt::{EnumData, EnumVariantData, StructData, VariantData},
|
||||||
ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData,
|
ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData,
|
||||||
ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData,
|
ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData,
|
||||||
},
|
},
|
||||||
@ -127,6 +127,9 @@ fn enum_variant_data_with_diagnostics(
|
|||||||
id: EnumVariantId,
|
id: EnumVariantId,
|
||||||
) -> (Arc<EnumVariantData>, DefDiagnostics);
|
) -> (Arc<EnumVariantData>, DefDiagnostics);
|
||||||
|
|
||||||
|
#[salsa::transparent]
|
||||||
|
#[salsa::invoke(VariantData::variant_data)]
|
||||||
|
fn variant_data(&self, id: VariantId) -> Arc<VariantData>;
|
||||||
#[salsa::transparent]
|
#[salsa::transparent]
|
||||||
#[salsa::invoke(ImplData::impl_data_query)]
|
#[salsa::invoke(ImplData::impl_data_query)]
|
||||||
fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
|
fn impl_data(&self, e: ImplId) -> Arc<ImplData>;
|
||||||
|
@ -716,6 +716,7 @@ pub struct Const {
|
|||||||
pub visibility: RawVisibilityId,
|
pub visibility: RawVisibilityId,
|
||||||
pub type_ref: Interned<TypeRef>,
|
pub type_ref: Interned<TypeRef>,
|
||||||
pub ast_id: FileAstId<ast::Const>,
|
pub ast_id: FileAstId<ast::Const>,
|
||||||
|
pub has_body: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
@ -446,7 +446,7 @@ fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
|
|||||||
let type_ref = self.lower_type_ref_opt(konst.ty());
|
let type_ref = self.lower_type_ref_opt(konst.ty());
|
||||||
let visibility = self.lower_visibility(konst);
|
let visibility = self.lower_visibility(konst);
|
||||||
let ast_id = self.source_ast_id_map.ast_id(konst);
|
let ast_id = self.source_ast_id_map.ast_id(konst);
|
||||||
let res = Const { name, visibility, type_ref, ast_id };
|
let res = Const { name, visibility, type_ref, ast_id, has_body: konst.body().is_some() };
|
||||||
id(self.data().consts.alloc(res))
|
id(self.data().consts.alloc(res))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,7 +357,7 @@ fn print_mod_item(&mut self, item: ModItem) {
|
|||||||
wln!(self, "}}");
|
wln!(self, "}}");
|
||||||
}
|
}
|
||||||
ModItem::Const(it) => {
|
ModItem::Const(it) => {
|
||||||
let Const { name, visibility, type_ref, ast_id } = &self.tree[it];
|
let Const { name, visibility, type_ref, ast_id, has_body: _ } = &self.tree[it];
|
||||||
self.print_ast_id(ast_id.erase());
|
self.print_ast_id(ast_id.erase());
|
||||||
self.print_visibility(*visibility);
|
self.print_visibility(*visibility);
|
||||||
w!(self, "const ");
|
w!(self, "const ");
|
||||||
|
@ -43,7 +43,7 @@ mod allow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec<IncorrectCase> {
|
pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec<IncorrectCase> {
|
||||||
let _p = tracing::span!(tracing::Level::INFO, "validate_module_item").entered();
|
let _p = tracing::span!(tracing::Level::INFO, "incorrect_case").entered();
|
||||||
let mut validator = DeclValidator::new(db);
|
let mut validator = DeclValidator::new(db);
|
||||||
validator.validate_item(owner);
|
validator.validate_item(owner);
|
||||||
validator.sink
|
validator.sink
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
use hir_expand::name;
|
use hir_expand::name;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
use rustc_pattern_analysis::constructor::Constructor;
|
||||||
use syntax::{ast, AstNode};
|
use syntax::{ast, AstNode};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use triomphe::Arc;
|
use triomphe::Arc;
|
||||||
@ -190,45 +191,45 @@ fn validate_match(
|
|||||||
let pattern_arena = Arena::new();
|
let pattern_arena = Arena::new();
|
||||||
let mut m_arms = Vec::with_capacity(arms.len());
|
let mut m_arms = Vec::with_capacity(arms.len());
|
||||||
let mut has_lowering_errors = false;
|
let mut has_lowering_errors = false;
|
||||||
|
// Note: Skipping the entire diagnostic rather than just not including a faulty match arm is
|
||||||
|
// preferred to avoid the chance of false positives.
|
||||||
for arm in arms {
|
for arm in arms {
|
||||||
if let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) {
|
let Some(pat_ty) = self.infer.type_of_pat.get(arm.pat) else {
|
||||||
// We only include patterns whose type matches the type
|
return;
|
||||||
// of the scrutinee expression. If we had an InvalidMatchArmPattern
|
};
|
||||||
// diagnostic or similar we could raise that in an else
|
|
||||||
// block here.
|
// We only include patterns whose type matches the type
|
||||||
//
|
// of the scrutinee expression. If we had an InvalidMatchArmPattern
|
||||||
// When comparing the types, we also have to consider that rustc
|
// diagnostic or similar we could raise that in an else
|
||||||
// will automatically de-reference the scrutinee expression type if
|
// block here.
|
||||||
// necessary.
|
//
|
||||||
//
|
// When comparing the types, we also have to consider that rustc
|
||||||
// FIXME we should use the type checker for this.
|
// will automatically de-reference the scrutinee expression type if
|
||||||
if (pat_ty == scrut_ty
|
// necessary.
|
||||||
|| scrut_ty
|
//
|
||||||
.as_reference()
|
// FIXME we should use the type checker for this.
|
||||||
.map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
|
if (pat_ty == scrut_ty
|
||||||
.unwrap_or(false))
|
|| scrut_ty
|
||||||
&& types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
|
.as_reference()
|
||||||
{
|
.map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
|
||||||
// If we had a NotUsefulMatchArm diagnostic, we could
|
.unwrap_or(false))
|
||||||
// check the usefulness of each pattern as we added it
|
&& types_of_subpatterns_do_match(arm.pat, &self.body, &self.infer)
|
||||||
// to the matrix here.
|
{
|
||||||
let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
|
// If we had a NotUsefulMatchArm diagnostic, we could
|
||||||
let m_arm = pat_analysis::MatchArm {
|
// check the usefulness of each pattern as we added it
|
||||||
pat: pattern_arena.alloc(pat),
|
// to the matrix here.
|
||||||
has_guard: arm.guard.is_some(),
|
let pat = self.lower_pattern(&cx, arm.pat, db, &mut has_lowering_errors);
|
||||||
arm_data: (),
|
let m_arm = pat_analysis::MatchArm {
|
||||||
};
|
pat: pattern_arena.alloc(pat),
|
||||||
m_arms.push(m_arm);
|
has_guard: arm.guard.is_some(),
|
||||||
if !has_lowering_errors {
|
arm_data: (),
|
||||||
continue;
|
};
|
||||||
}
|
m_arms.push(m_arm);
|
||||||
|
if !has_lowering_errors {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If the pattern type doesn't fit the match expression, we skip this diagnostic.
|
||||||
// If we can't resolve the type of a pattern, or the pattern type doesn't
|
|
||||||
// fit the match expression, we skip this diagnostic. Skipping the entire
|
|
||||||
// diagnostic rather than just not including this match arm is preferred
|
|
||||||
// to avoid the chance of false positives.
|
|
||||||
cov_mark::hit!(validate_match_bailed_out);
|
cov_mark::hit!(validate_match_bailed_out);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -266,15 +267,17 @@ fn validate_block(&mut self, db: &dyn HirDatabase, expr: &Expr) {
|
|||||||
|
|
||||||
let mut have_errors = false;
|
let mut have_errors = false;
|
||||||
let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors);
|
let deconstructed_pat = self.lower_pattern(&cx, pat, db, &mut have_errors);
|
||||||
|
|
||||||
|
// optimization, wildcard trivially hold
|
||||||
|
if have_errors || matches!(deconstructed_pat.ctor(), Constructor::Wildcard) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
let match_arm = rustc_pattern_analysis::MatchArm {
|
let match_arm = rustc_pattern_analysis::MatchArm {
|
||||||
pat: pattern_arena.alloc(deconstructed_pat),
|
pat: pattern_arena.alloc(deconstructed_pat),
|
||||||
has_guard: false,
|
has_guard: false,
|
||||||
arm_data: (),
|
arm_data: (),
|
||||||
};
|
};
|
||||||
if have_errors {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let report = match cx.compute_match_usefulness(&[match_arm], ty.clone()) {
|
let report = match cx.compute_match_usefulness(&[match_arm], ty.clone()) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -531,8 +534,16 @@ fn types_of_subpatterns_do_match(pat: PatId, body: &Body, infer: &InferenceResul
|
|||||||
fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) {
|
fn walk(pat: PatId, body: &Body, infer: &InferenceResult, has_type_mismatches: &mut bool) {
|
||||||
match infer.type_mismatch_for_pat(pat) {
|
match infer.type_mismatch_for_pat(pat) {
|
||||||
Some(_) => *has_type_mismatches = true,
|
Some(_) => *has_type_mismatches = true,
|
||||||
|
None if *has_type_mismatches => (),
|
||||||
None => {
|
None => {
|
||||||
body[pat].walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches))
|
let pat = &body[pat];
|
||||||
|
if let Pat::ConstBlock(expr) | Pat::Lit(expr) = *pat {
|
||||||
|
*has_type_mismatches |= infer.type_mismatch_for_expr(expr).is_some();
|
||||||
|
if *has_type_mismatches {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pat.walk_child_pats(|subpat| walk(subpat, body, infer, has_type_mismatches))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
//! Interface with `rustc_pattern_analysis`.
|
//! Interface with `rustc_pattern_analysis`.
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
|
use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
|
||||||
|
use once_cell::unsync::Lazy;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use rustc_pattern_analysis::{
|
use rustc_pattern_analysis::{
|
||||||
constructor::{Constructor, ConstructorSet, VariantVisibility},
|
constructor::{Constructor, ConstructorSet, VariantVisibility},
|
||||||
@ -91,20 +91,13 @@ pub(crate) fn compute_match_usefulness(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_uninhabited(&self, ty: &Ty) -> bool {
|
fn is_uninhabited(&self, ty: &Ty) -> bool {
|
||||||
is_ty_uninhabited_from(ty, self.module, self.db)
|
is_ty_uninhabited_from(self.db, ty, self.module)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`.
|
/// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`.
|
||||||
fn is_foreign_non_exhaustive_enum(&self, ty: &Ty) -> bool {
|
fn is_foreign_non_exhaustive(&self, adt: hir_def::AdtId) -> bool {
|
||||||
match ty.as_adt() {
|
let is_local = adt.krate(self.db.upcast()) == self.module.krate();
|
||||||
Some((adt @ hir_def::AdtId::EnumId(_), _)) => {
|
!is_local && self.db.attrs(adt.into()).by_key("non_exhaustive").exists()
|
||||||
let has_non_exhaustive_attr =
|
|
||||||
self.db.attrs(adt.into()).by_key("non_exhaustive").exists();
|
|
||||||
let is_local = adt.module(self.db.upcast()).krate() == self.module.krate();
|
|
||||||
has_non_exhaustive_attr && !is_local
|
|
||||||
}
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variant_id_for_adt(
|
fn variant_id_for_adt(
|
||||||
@ -376,24 +369,21 @@ fn ctor_sub_tys<'a>(
|
|||||||
single(subst_ty)
|
single(subst_ty)
|
||||||
} else {
|
} else {
|
||||||
let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
|
let variant = Self::variant_id_for_adt(self.db, ctor, adt).unwrap();
|
||||||
let (adt, _) = ty.as_adt().unwrap();
|
|
||||||
|
|
||||||
let adt_is_local =
|
|
||||||
variant.module(self.db.upcast()).krate() == self.module.krate();
|
|
||||||
// Whether we must not match the fields of this variant exhaustively.
|
// Whether we must not match the fields of this variant exhaustively.
|
||||||
let is_non_exhaustive =
|
let is_non_exhaustive = Lazy::new(|| self.is_foreign_non_exhaustive(adt));
|
||||||
self.db.attrs(variant.into()).by_key("non_exhaustive").exists()
|
let visibilities = Lazy::new(|| self.db.field_visibilities(variant));
|
||||||
&& !adt_is_local;
|
|
||||||
let visibilities = self.db.field_visibilities(variant);
|
|
||||||
|
|
||||||
self.list_variant_fields(ty, variant)
|
self.list_variant_fields(ty, variant)
|
||||||
.map(move |(fid, ty)| {
|
.map(move |(fid, ty)| {
|
||||||
let is_visible = matches!(adt, hir_def::AdtId::EnumId(..))
|
let is_visible = || {
|
||||||
|| visibilities[fid]
|
matches!(adt, hir_def::AdtId::EnumId(..))
|
||||||
.is_visible_from(self.db.upcast(), self.module);
|
|| visibilities[fid]
|
||||||
|
.is_visible_from(self.db.upcast(), self.module)
|
||||||
|
};
|
||||||
let is_uninhabited = self.is_uninhabited(&ty);
|
let is_uninhabited = self.is_uninhabited(&ty);
|
||||||
let private_uninhabited =
|
let private_uninhabited =
|
||||||
is_uninhabited && (!is_visible || is_non_exhaustive);
|
is_uninhabited && (!is_visible() || *is_non_exhaustive);
|
||||||
(ty, PrivateUninhabitedField(private_uninhabited))
|
(ty, PrivateUninhabitedField(private_uninhabited))
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
@ -445,17 +435,20 @@ fn ctors_for_ty(
|
|||||||
TyKind::Scalar(Scalar::Char) => unhandled(),
|
TyKind::Scalar(Scalar::Char) => unhandled(),
|
||||||
TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
|
TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
|
||||||
TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
|
TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
|
||||||
TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), subst) => {
|
&TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => {
|
||||||
let enum_data = cx.db.enum_data(*enum_id);
|
let enum_data = cx.db.enum_data(enum_id);
|
||||||
let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty);
|
let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt);
|
||||||
|
|
||||||
if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
|
if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
|
||||||
ConstructorSet::NoConstructors
|
ConstructorSet::NoConstructors
|
||||||
} else {
|
} else {
|
||||||
let mut variants = FxHashMap::default();
|
let mut variants = FxHashMap::with_capacity_and_hasher(
|
||||||
|
enum_data.variants.len(),
|
||||||
|
Default::default(),
|
||||||
|
);
|
||||||
for (i, &(variant, _)) in enum_data.variants.iter().enumerate() {
|
for (i, &(variant, _)) in enum_data.variants.iter().enumerate() {
|
||||||
let is_uninhabited =
|
let is_uninhabited =
|
||||||
is_enum_variant_uninhabited_from(variant, subst, cx.module, cx.db);
|
is_enum_variant_uninhabited_from(cx.db, variant, subst, cx.module);
|
||||||
let visibility = if is_uninhabited {
|
let visibility = if is_uninhabited {
|
||||||
VariantVisibility::Empty
|
VariantVisibility::Empty
|
||||||
} else {
|
} else {
|
||||||
@ -506,7 +499,7 @@ fn write_variant_name(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn bug(&self, fmt: fmt::Arguments<'_>) {
|
fn bug(&self, fmt: fmt::Arguments<'_>) {
|
||||||
debug!("{}", fmt)
|
never!("{}", fmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complexity_exceeded(&self) -> Result<(), Self::Error> {
|
fn complexity_exceeded(&self) -> Result<(), Self::Error> {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
use hir_def::{
|
use hir_def::{
|
||||||
body::Body,
|
body::Body,
|
||||||
hir::{Expr, ExprId, UnaryOp},
|
hir::{Expr, ExprId, UnaryOp},
|
||||||
resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
|
resolver::{resolver_for_expr, ResolveValueResult, Resolver, ValueNs},
|
||||||
DefWithBodyId,
|
DefWithBodyId,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -13,9 +13,9 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
|
pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
|
||||||
let infer = db.infer(def);
|
let _p = tracing::span!(tracing::Level::INFO, "missing_unsafe",);
|
||||||
let mut res = Vec::new();
|
|
||||||
|
|
||||||
|
let mut res = Vec::new();
|
||||||
let is_unsafe = match def {
|
let is_unsafe = match def {
|
||||||
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
|
DefWithBodyId::FunctionId(it) => db.function_data(it).has_unsafe_kw(),
|
||||||
DefWithBodyId::StaticId(_)
|
DefWithBodyId::StaticId(_)
|
||||||
@ -28,6 +28,7 @@ pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let body = db.body(def);
|
let body = db.body(def);
|
||||||
|
let infer = db.infer(def);
|
||||||
unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
|
unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
|
||||||
if !expr.inside_unsafe_block {
|
if !expr.inside_unsafe_block {
|
||||||
res.push(expr.expr);
|
res.push(expr.expr);
|
||||||
@ -51,14 +52,24 @@ pub fn unsafe_expressions(
|
|||||||
current: ExprId,
|
current: ExprId,
|
||||||
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
|
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
|
||||||
) {
|
) {
|
||||||
walk_unsafe(db, infer, def, body, current, false, unsafe_expr_cb)
|
walk_unsafe(
|
||||||
|
db,
|
||||||
|
infer,
|
||||||
|
body,
|
||||||
|
&mut resolver_for_expr(db.upcast(), def, current),
|
||||||
|
def,
|
||||||
|
current,
|
||||||
|
false,
|
||||||
|
unsafe_expr_cb,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn walk_unsafe(
|
fn walk_unsafe(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
infer: &InferenceResult,
|
infer: &InferenceResult,
|
||||||
def: DefWithBodyId,
|
|
||||||
body: &Body,
|
body: &Body,
|
||||||
|
resolver: &mut Resolver,
|
||||||
|
def: DefWithBodyId,
|
||||||
current: ExprId,
|
current: ExprId,
|
||||||
inside_unsafe_block: bool,
|
inside_unsafe_block: bool,
|
||||||
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
|
unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
|
||||||
@ -73,13 +84,14 @@ fn walk_unsafe(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Path(path) => {
|
Expr::Path(path) => {
|
||||||
let resolver = resolver_for_expr(db.upcast(), def, current);
|
let g = resolver.update_to_inner_scope(db.upcast(), def, current);
|
||||||
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
|
let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path);
|
||||||
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
|
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
|
||||||
if db.static_data(id).mutable {
|
if db.static_data(id).mutable {
|
||||||
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
resolver.reset_to_guard(g);
|
||||||
}
|
}
|
||||||
Expr::MethodCall { .. } => {
|
Expr::MethodCall { .. } => {
|
||||||
if infer
|
if infer
|
||||||
@ -97,13 +109,13 @@ fn walk_unsafe(
|
|||||||
}
|
}
|
||||||
Expr::Unsafe { .. } => {
|
Expr::Unsafe { .. } => {
|
||||||
return expr.walk_child_exprs(|child| {
|
return expr.walk_child_exprs(|child| {
|
||||||
walk_unsafe(db, infer, def, body, child, true, unsafe_expr_cb);
|
walk_unsafe(db, infer, body, resolver, def, child, true, unsafe_expr_cb);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
expr.walk_child_exprs(|child| {
|
expr.walk_child_exprs(|child| {
|
||||||
walk_unsafe(db, infer, def, body, child, inside_unsafe_block, unsafe_expr_cb);
|
walk_unsafe(db, infer, body, resolver, def, child, inside_unsafe_block, unsafe_expr_cb);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -432,6 +432,7 @@ pub struct InferenceResult {
|
|||||||
/// Whether there are any type-mismatching errors in the result.
|
/// Whether there are any type-mismatching errors in the result.
|
||||||
pub(crate) has_errors: bool,
|
pub(crate) has_errors: bool,
|
||||||
/// Interned common types to return references to.
|
/// Interned common types to return references to.
|
||||||
|
// FIXME: Move this into `InferenceContext`
|
||||||
standard_types: InternedStandardTypes,
|
standard_types: InternedStandardTypes,
|
||||||
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
/// Stores the types which were implicitly dereferenced in pattern binding modes.
|
||||||
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
|
pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
|
||||||
|
@ -5,42 +5,36 @@
|
|||||||
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
|
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
|
||||||
DebruijnIndex,
|
DebruijnIndex,
|
||||||
};
|
};
|
||||||
use hir_def::{
|
use hir_def::{visibility::Visibility, AdtId, EnumVariantId, HasModule, ModuleId, VariantId};
|
||||||
attr::Attrs, data::adt::VariantData, visibility::Visibility, AdtId, EnumVariantId, HasModule,
|
|
||||||
ModuleId, VariantId,
|
|
||||||
};
|
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
consteval::try_const_usize, db::HirDatabase, Binders, Interner, Substitution, Ty, TyKind,
|
consteval::try_const_usize, db::HirDatabase, Binders, Interner, Substitution, Ty, TyKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME: Turn this into a query, it can be quite slow
|
||||||
/// Checks whether a type is visibly uninhabited from a particular module.
|
/// Checks whether a type is visibly uninhabited from a particular module.
|
||||||
pub(crate) fn is_ty_uninhabited_from(ty: &Ty, target_mod: ModuleId, db: &dyn HirDatabase) -> bool {
|
pub(crate) fn is_ty_uninhabited_from(db: &dyn HirDatabase, ty: &Ty, target_mod: ModuleId) -> bool {
|
||||||
|
let _p = tracing::span!(tracing::Level::INFO, "is_ty_uninhabited_from", ?ty);
|
||||||
let mut uninhabited_from =
|
let mut uninhabited_from =
|
||||||
UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
|
UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
|
||||||
let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
|
let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
|
||||||
inhabitedness == BREAK_VISIBLY_UNINHABITED
|
inhabitedness == BREAK_VISIBLY_UNINHABITED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Turn this into a query, it can be quite slow
|
||||||
/// Checks whether a variant is visibly uninhabited from a particular module.
|
/// Checks whether a variant is visibly uninhabited from a particular module.
|
||||||
pub(crate) fn is_enum_variant_uninhabited_from(
|
pub(crate) fn is_enum_variant_uninhabited_from(
|
||||||
|
db: &dyn HirDatabase,
|
||||||
variant: EnumVariantId,
|
variant: EnumVariantId,
|
||||||
subst: &Substitution,
|
subst: &Substitution,
|
||||||
target_mod: ModuleId,
|
target_mod: ModuleId,
|
||||||
db: &dyn HirDatabase,
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let is_local = variant.module(db.upcast()).krate() == target_mod.krate();
|
let _p = tracing::span!(tracing::Level::INFO, "is_enum_variant_uninhabited_from",);
|
||||||
|
|
||||||
let mut uninhabited_from =
|
let mut uninhabited_from =
|
||||||
UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
|
UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
|
||||||
let inhabitedness = uninhabited_from.visit_variant(
|
let inhabitedness = uninhabited_from.visit_variant(variant.into(), subst);
|
||||||
variant.into(),
|
|
||||||
&db.enum_variant_data(variant).variant_data,
|
|
||||||
subst,
|
|
||||||
&db.attrs(variant.into()),
|
|
||||||
is_local,
|
|
||||||
);
|
|
||||||
inhabitedness == BREAK_VISIBLY_UNINHABITED
|
inhabitedness == BREAK_VISIBLY_UNINHABITED
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,34 +92,18 @@ fn interner(&self) -> Interner {
|
|||||||
|
|
||||||
impl UninhabitedFrom<'_> {
|
impl UninhabitedFrom<'_> {
|
||||||
fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
|
fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<VisiblyUninhabited> {
|
||||||
let attrs = self.db.attrs(adt.into());
|
|
||||||
let adt_non_exhaustive = attrs.by_key("non_exhaustive").exists();
|
|
||||||
let is_local = adt.module(self.db.upcast()).krate() == self.target_mod.krate();
|
|
||||||
if adt_non_exhaustive && !is_local {
|
|
||||||
return CONTINUE_OPAQUELY_INHABITED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// An ADT is uninhabited iff all its variants uninhabited.
|
// An ADT is uninhabited iff all its variants uninhabited.
|
||||||
match adt {
|
match adt {
|
||||||
// rustc: For now, `union`s are never considered uninhabited.
|
// rustc: For now, `union`s are never considered uninhabited.
|
||||||
AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
|
AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
|
||||||
AdtId::StructId(s) => {
|
AdtId::StructId(s) => self.visit_variant(s.into(), subst),
|
||||||
let struct_data = self.db.struct_data(s);
|
|
||||||
self.visit_variant(s.into(), &struct_data.variant_data, subst, &attrs, is_local)
|
|
||||||
}
|
|
||||||
AdtId::EnumId(e) => {
|
AdtId::EnumId(e) => {
|
||||||
let enum_data = self.db.enum_data(e);
|
let enum_data = self.db.enum_data(e);
|
||||||
|
|
||||||
for &(variant, _) in enum_data.variants.iter() {
|
for &(variant, _) in enum_data.variants.iter() {
|
||||||
let variant_inhabitedness = self.visit_variant(
|
let variant_inhabitedness = self.visit_variant(variant.into(), subst);
|
||||||
variant.into(),
|
|
||||||
&self.db.enum_variant_data(variant).variant_data,
|
|
||||||
subst,
|
|
||||||
&self.db.attrs(variant.into()),
|
|
||||||
is_local,
|
|
||||||
);
|
|
||||||
match variant_inhabitedness {
|
match variant_inhabitedness {
|
||||||
Break(VisiblyUninhabited) => continue,
|
Break(VisiblyUninhabited) => (),
|
||||||
Continue(()) => return CONTINUE_OPAQUELY_INHABITED,
|
Continue(()) => return CONTINUE_OPAQUELY_INHABITED,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,34 +115,36 @@ fn visit_adt(&mut self, adt: AdtId, subst: &Substitution) -> ControlFlow<Visibly
|
|||||||
fn visit_variant(
|
fn visit_variant(
|
||||||
&mut self,
|
&mut self,
|
||||||
variant: VariantId,
|
variant: VariantId,
|
||||||
variant_data: &VariantData,
|
|
||||||
subst: &Substitution,
|
subst: &Substitution,
|
||||||
attrs: &Attrs,
|
|
||||||
is_local: bool,
|
|
||||||
) -> ControlFlow<VisiblyUninhabited> {
|
) -> ControlFlow<VisiblyUninhabited> {
|
||||||
let non_exhaustive_field_list = attrs.by_key("non_exhaustive").exists();
|
let is_local = variant.krate(self.db.upcast()) == self.target_mod.krate();
|
||||||
if non_exhaustive_field_list && !is_local {
|
if !is_local && self.db.attrs(variant.into()).by_key("non_exhaustive").exists() {
|
||||||
|
return CONTINUE_OPAQUELY_INHABITED;
|
||||||
|
}
|
||||||
|
|
||||||
|
let variant_data = self.db.variant_data(variant);
|
||||||
|
let fields = variant_data.fields();
|
||||||
|
if fields.is_empty() {
|
||||||
return CONTINUE_OPAQUELY_INHABITED;
|
return CONTINUE_OPAQUELY_INHABITED;
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_enum = matches!(variant, VariantId::EnumVariantId(..));
|
let is_enum = matches!(variant, VariantId::EnumVariantId(..));
|
||||||
let field_tys = self.db.field_types(variant);
|
let field_tys = self.db.field_types(variant);
|
||||||
let field_vis = self.db.field_visibilities(variant);
|
let field_vis = if is_enum { None } else { Some(self.db.field_visibilities(variant)) };
|
||||||
|
|
||||||
for (fid, _) in variant_data.fields().iter() {
|
for (fid, _) in fields.iter() {
|
||||||
self.visit_field(field_vis[fid], &field_tys[fid], subst, is_enum)?;
|
self.visit_field(field_vis.as_ref().map(|it| it[fid]), &field_tys[fid], subst)?;
|
||||||
}
|
}
|
||||||
CONTINUE_OPAQUELY_INHABITED
|
CONTINUE_OPAQUELY_INHABITED
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_field(
|
fn visit_field(
|
||||||
&mut self,
|
&mut self,
|
||||||
vis: Visibility,
|
vis: Option<Visibility>,
|
||||||
ty: &Binders<Ty>,
|
ty: &Binders<Ty>,
|
||||||
subst: &Substitution,
|
subst: &Substitution,
|
||||||
is_enum: bool,
|
|
||||||
) -> ControlFlow<VisiblyUninhabited> {
|
) -> ControlFlow<VisiblyUninhabited> {
|
||||||
if is_enum || vis.is_visible_from(self.db.upcast(), self.target_mod) {
|
if vis.map_or(true, |it| it.is_visible_from(self.db.upcast(), self.target_mod)) {
|
||||||
let ty = ty.clone().substitute(Interner, subst);
|
let ty = ty.clone().substitute(Interner, subst);
|
||||||
ty.visit_with(self, DebruijnIndex::INNERMOST)
|
ty.visit_with(self, DebruijnIndex::INNERMOST)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1706,7 +1706,7 @@ fn current_loop_end(&mut self) -> Result<BasicBlockId> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_uninhabited(&self, expr_id: ExprId) -> bool {
|
fn is_uninhabited(&self, expr_id: ExprId) -> bool {
|
||||||
is_ty_uninhabited_from(&self.infer[expr_id], self.owner.module(self.db.upcast()), self.db)
|
is_ty_uninhabited_from(self.db, &self.infer[expr_id], self.owner.module(self.db.upcast()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and
|
/// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and
|
||||||
|
@ -548,8 +548,7 @@ pub fn diagnostics(
|
|||||||
acc: &mut Vec<AnyDiagnostic>,
|
acc: &mut Vec<AnyDiagnostic>,
|
||||||
style_lints: bool,
|
style_lints: bool,
|
||||||
) {
|
) {
|
||||||
let name = self.name(db);
|
let _p = tracing::span!(tracing::Level::INFO, "Module::diagnostics", name = ?self.name(db));
|
||||||
let _p = tracing::span!(tracing::Level::INFO, "Module::diagnostics", ?name);
|
|
||||||
let def_map = self.id.def_map(db.upcast());
|
let def_map = self.id.def_map(db.upcast());
|
||||||
for diag in def_map.diagnostics() {
|
for diag in def_map.diagnostics() {
|
||||||
if diag.in_module != self.id.local_id {
|
if diag.in_module != self.id.local_id {
|
||||||
@ -684,7 +683,7 @@ pub fn diagnostics(
|
|||||||
let items = &db.trait_data(trait_.into()).items;
|
let items = &db.trait_data(trait_.into()).items;
|
||||||
let required_items = items.iter().filter(|&(_, assoc)| match *assoc {
|
let required_items = items.iter().filter(|&(_, assoc)| match *assoc {
|
||||||
AssocItemId::FunctionId(it) => !db.function_data(it).has_body(),
|
AssocItemId::FunctionId(it) => !db.function_data(it).has_body(),
|
||||||
AssocItemId::ConstId(id) => Const::from(id).value(db).is_none(),
|
AssocItemId::ConstId(id) => !db.const_data(id).has_body,
|
||||||
AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(),
|
AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(),
|
||||||
});
|
});
|
||||||
impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().filter_map(
|
impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().filter_map(
|
||||||
@ -1628,7 +1627,6 @@ pub fn diagnostics(
|
|||||||
acc: &mut Vec<AnyDiagnostic>,
|
acc: &mut Vec<AnyDiagnostic>,
|
||||||
style_lints: bool,
|
style_lints: bool,
|
||||||
) {
|
) {
|
||||||
db.unwind_if_cancelled();
|
|
||||||
let krate = self.module(db).id.krate();
|
let krate = self.module(db).id.krate();
|
||||||
|
|
||||||
let (body, source_map) = db.body_with_source_map(self.into());
|
let (body, source_map) = db.body_with_source_map(self.into());
|
||||||
@ -1762,7 +1760,9 @@ pub fn diagnostics(
|
|||||||
need_mut = &mir::MutabilityReason::Not;
|
need_mut = &mir::MutabilityReason::Not;
|
||||||
}
|
}
|
||||||
let local = Local { parent: self.into(), binding_id };
|
let local = Local { parent: self.into(), binding_id };
|
||||||
match (need_mut, local.is_mut(db)) {
|
let is_mut = body[binding_id].mode == BindingAnnotation::Mutable;
|
||||||
|
|
||||||
|
match (need_mut, is_mut) {
|
||||||
(mir::MutabilityReason::Unused, _) => {
|
(mir::MutabilityReason::Unused, _) => {
|
||||||
let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with('_'));
|
let should_ignore = matches!(body[binding_id].name.as_str(), Some(it) if it.starts_with('_'));
|
||||||
if !should_ignore {
|
if !should_ignore {
|
||||||
|
@ -317,7 +317,8 @@ fn main() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn mismatched_types_issue_15883() {
|
fn mismatched_types_issue_15883() {
|
||||||
// Check we don't panic.
|
// Check we don't panic.
|
||||||
check_diagnostics_no_bails(
|
cov_mark::check!(validate_match_bailed_out);
|
||||||
|
check_diagnostics(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: option
|
//- minicore: option
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -320,13 +320,11 @@ pub fn diagnostics(
|
|||||||
let module = sema.file_to_module_def(file_id);
|
let module = sema.file_to_module_def(file_id);
|
||||||
|
|
||||||
let ctx = DiagnosticsContext { config, sema, resolve };
|
let ctx = DiagnosticsContext { config, sema, resolve };
|
||||||
if module.is_none() {
|
|
||||||
handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut diags = Vec::new();
|
let mut diags = Vec::new();
|
||||||
if let Some(m) = module {
|
match module {
|
||||||
m.diagnostics(db, &mut diags, config.style_lints);
|
Some(m) => m.diagnostics(db, &mut diags, config.style_lints),
|
||||||
|
None => handlers::unlinked_file::unlinked_file(&ctx, &mut res, file_id),
|
||||||
}
|
}
|
||||||
|
|
||||||
for diag in diags {
|
for diag in diags {
|
||||||
@ -409,6 +407,11 @@ pub fn diagnostics(
|
|||||||
res.push(d)
|
res.push(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res.retain(|d| {
|
||||||
|
!(ctx.config.disabled.contains(d.code.as_str())
|
||||||
|
|| ctx.config.disable_experimental && d.experimental)
|
||||||
|
});
|
||||||
|
|
||||||
let mut diagnostics_of_range = res
|
let mut diagnostics_of_range = res
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter_map(|it| {
|
.filter_map(|it| {
|
||||||
@ -421,9 +424,14 @@ pub fn diagnostics(
|
|||||||
})
|
})
|
||||||
.collect::<FxHashMap<_, _>>();
|
.collect::<FxHashMap<_, _>>();
|
||||||
|
|
||||||
|
if diagnostics_of_range.is_empty() {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
let mut rustc_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();
|
let mut rustc_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();
|
||||||
let mut clippy_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();
|
let mut clippy_stack: FxHashMap<String, Vec<Severity>> = FxHashMap::default();
|
||||||
|
|
||||||
|
// FIXME: This becomes quite expensive for big files
|
||||||
handle_lint_attributes(
|
handle_lint_attributes(
|
||||||
&ctx.sema,
|
&ctx.sema,
|
||||||
parse.syntax(),
|
parse.syntax(),
|
||||||
@ -432,11 +440,7 @@ pub fn diagnostics(
|
|||||||
&mut diagnostics_of_range,
|
&mut diagnostics_of_range,
|
||||||
);
|
);
|
||||||
|
|
||||||
res.retain(|d| {
|
res.retain(|d| d.severity != Severity::Allow);
|
||||||
d.severity != Severity::Allow
|
|
||||||
&& !ctx.config.disabled.contains(d.code.as_str())
|
|
||||||
&& !(ctx.config.disable_experimental && d.experimental)
|
|
||||||
});
|
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
@ -476,6 +480,7 @@ fn handle_lint_attributes(
|
|||||||
clippy_stack: &mut FxHashMap<String, Vec<Severity>>,
|
clippy_stack: &mut FxHashMap<String, Vec<Severity>>,
|
||||||
diagnostics_of_range: &mut FxHashMap<InFile<SyntaxNode>, &mut Diagnostic>,
|
diagnostics_of_range: &mut FxHashMap<InFile<SyntaxNode>, &mut Diagnostic>,
|
||||||
) {
|
) {
|
||||||
|
let _g = tracing::span!(tracing::Level::INFO, "handle_lint_attributes").entered();
|
||||||
let file_id = sema.hir_file_for(root);
|
let file_id = sema.hir_file_for(root);
|
||||||
let preorder = root.preorder();
|
let preorder = root.preorder();
|
||||||
for ev in preorder {
|
for ev in preorder {
|
||||||
@ -486,24 +491,24 @@ fn handle_lint_attributes(
|
|||||||
stack.push(severity);
|
stack.push(severity);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if let Some(x) =
|
if let Some(it) =
|
||||||
diagnostics_of_range.get_mut(&InFile { file_id, value: node.clone() })
|
diagnostics_of_range.get_mut(&InFile { file_id, value: node.clone() })
|
||||||
{
|
{
|
||||||
const EMPTY_LINTS: &[&str] = &[];
|
const EMPTY_LINTS: &[&str] = &[];
|
||||||
let (names, stack) = match x.code {
|
let (names, stack) = match it.code {
|
||||||
DiagnosticCode::RustcLint(name) => (
|
DiagnosticCode::RustcLint(name) => (
|
||||||
RUSTC_LINT_GROUPS_DICT.get(name).map_or(EMPTY_LINTS, |x| &**x),
|
RUSTC_LINT_GROUPS_DICT.get(name).map_or(EMPTY_LINTS, |it| &**it),
|
||||||
&mut *rustc_stack,
|
&mut *rustc_stack,
|
||||||
),
|
),
|
||||||
DiagnosticCode::Clippy(name) => (
|
DiagnosticCode::Clippy(name) => (
|
||||||
CLIPPY_LINT_GROUPS_DICT.get(name).map_or(EMPTY_LINTS, |x| &**x),
|
CLIPPY_LINT_GROUPS_DICT.get(name).map_or(EMPTY_LINTS, |it| &**it),
|
||||||
&mut *clippy_stack,
|
&mut *clippy_stack,
|
||||||
),
|
),
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
for &name in names {
|
for &name in names {
|
||||||
if let Some(s) = stack.get(name).and_then(|x| x.last()) {
|
if let Some(s) = stack.get(name).and_then(|it| it.last()) {
|
||||||
x.severity = *s;
|
it.severity = *s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -571,8 +576,8 @@ fn parse_lint_attribute(
|
|||||||
if let Some(lint) = lint.as_single_name_ref() {
|
if let Some(lint) = lint.as_single_name_ref() {
|
||||||
job(rustc_stack.entry(lint.to_string()).or_default(), severity);
|
job(rustc_stack.entry(lint.to_string()).or_default(), severity);
|
||||||
}
|
}
|
||||||
if let Some(tool) = lint.qualifier().and_then(|x| x.as_single_name_ref()) {
|
if let Some(tool) = lint.qualifier().and_then(|it| it.as_single_name_ref()) {
|
||||||
if let Some(name_ref) = &lint.segment().and_then(|x| x.name_ref()) {
|
if let Some(name_ref) = &lint.segment().and_then(|it| it.name_ref()) {
|
||||||
if tool.to_string() == "clippy" {
|
if tool.to_string() == "clippy" {
|
||||||
job(clippy_stack.entry(name_ref.to_string()).or_default(), severity);
|
job(clippy_stack.entry(name_ref.to_string()).or_default(), severity);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ fn integrated_highlighting_benchmark() {
|
|||||||
};
|
};
|
||||||
let load_cargo_config = LoadCargoConfig {
|
let load_cargo_config = LoadCargoConfig {
|
||||||
load_out_dirs_from_check: true,
|
load_out_dirs_from_check: true,
|
||||||
with_proc_macro_server: ProcMacroServerChoice::None,
|
with_proc_macro_server: ProcMacroServerChoice::Sysroot,
|
||||||
prefill_caches: false,
|
prefill_caches: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ fn integrated_completion_benchmark() {
|
|||||||
};
|
};
|
||||||
let load_cargo_config = LoadCargoConfig {
|
let load_cargo_config = LoadCargoConfig {
|
||||||
load_out_dirs_from_check: true,
|
load_out_dirs_from_check: true,
|
||||||
with_proc_macro_server: ProcMacroServerChoice::None,
|
with_proc_macro_server: ProcMacroServerChoice::Sysroot,
|
||||||
prefill_caches: true,
|
prefill_caches: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -262,7 +262,7 @@ fn integrated_diagnostics_benchmark() {
|
|||||||
};
|
};
|
||||||
let load_cargo_config = LoadCargoConfig {
|
let load_cargo_config = LoadCargoConfig {
|
||||||
load_out_dirs_from_check: true,
|
load_out_dirs_from_check: true,
|
||||||
with_proc_macro_server: ProcMacroServerChoice::None,
|
with_proc_macro_server: ProcMacroServerChoice::Sysroot,
|
||||||
prefill_caches: true,
|
prefill_caches: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -300,7 +300,7 @@ fn integrated_diagnostics_benchmark() {
|
|||||||
.diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
|
.diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let _g = crate::tracing::hprof::init("*>1");
|
let _g = crate::tracing::hprof::init("*");
|
||||||
|
|
||||||
{
|
{
|
||||||
let _it = stdx::timeit("change");
|
let _it = stdx::timeit("change");
|
||||||
|
Loading…
Reference in New Issue
Block a user