Skip to content

Commit 1c58418

Browse files
authored
Merge pull request rust-lang#19824 from ChayimFriedman2/lints-again
fix: Fix cache problems with lints level
2 parents 2580d83 + 31b4808 commit 1c58418

File tree

2 files changed

+60
-164
lines changed

2 files changed

+60
-164
lines changed

src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,4 +915,47 @@ fn foo() {
915915
"#,
916916
);
917917
}
918+
919+
#[test]
920+
fn regression_19823() {
921+
check_diagnostics(
922+
r#"
923+
pub trait FooTrait {
924+
unsafe fn method1();
925+
unsafe fn method2();
926+
}
927+
928+
unsafe fn some_unsafe_fn() {}
929+
930+
macro_rules! impl_foo {
931+
() => {
932+
unsafe fn method1() {
933+
some_unsafe_fn();
934+
}
935+
unsafe fn method2() {
936+
some_unsafe_fn();
937+
}
938+
};
939+
}
940+
941+
pub struct S1;
942+
#[allow(unsafe_op_in_unsafe_fn)]
943+
impl FooTrait for S1 {
944+
unsafe fn method1() {
945+
some_unsafe_fn();
946+
}
947+
948+
unsafe fn method2() {
949+
some_unsafe_fn();
950+
}
951+
}
952+
953+
pub struct S2;
954+
#[allow(unsafe_op_in_unsafe_fn)]
955+
impl FooTrait for S2 {
956+
impl_foo!();
957+
}
958+
"#,
959+
);
960+
}
918961
}

src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs

Lines changed: 17 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,11 @@ mod handlers {
8383
#[cfg(test)]
8484
mod tests;
8585

86-
use std::{collections::hash_map, iter, sync::LazyLock};
86+
use std::{iter, sync::LazyLock};
8787

8888
use either::Either;
8989
use hir::{
90-
Crate, DisplayTarget, HirFileId, InFile, Semantics, db::ExpandDatabase,
91-
diagnostics::AnyDiagnostic,
90+
Crate, DisplayTarget, InFile, Semantics, db::ExpandDatabase, diagnostics::AnyDiagnostic,
9291
};
9392
use ide_db::{
9493
EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap,
@@ -513,13 +512,7 @@ pub fn semantic_diagnostics(
513512

514513
// The edition isn't accurate (each diagnostics may have its own edition due to macros),
515514
// but it's okay as it's only being used for error recovery.
516-
handle_lints(
517-
&ctx.sema,
518-
&mut FxHashMap::default(),
519-
&mut lints,
520-
&mut Vec::new(),
521-
editioned_file_id.edition(db),
522-
);
515+
handle_lints(&ctx.sema, &mut lints, editioned_file_id.edition(db));
523516

524517
res.retain(|d| d.severity != Severity::Allow);
525518

@@ -584,8 +577,6 @@ fn handle_diag_from_macros(
584577
true
585578
}
586579

587-
// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
588-
589580
struct BuiltLint {
590581
lint: &'static Lint,
591582
groups: Vec<&'static str>,
@@ -629,9 +620,7 @@ fn build_lints_map(
629620

630621
fn handle_lints(
631622
sema: &Semantics<'_, RootDatabase>,
632-
cache: &mut FxHashMap<HirFileId, FxHashMap<SmolStr, SeverityAttr>>,
633623
diagnostics: &mut [(InFile<SyntaxNode>, &mut Diagnostic)],
634-
cache_stack: &mut Vec<HirFileId>,
635624
edition: Edition,
636625
) {
637626
for (node, diag) in diagnostics {
@@ -645,7 +634,8 @@ fn handle_lints(
645634
diag.severity = default_severity;
646635
}
647636

648-
let mut diag_severity = fill_lint_attrs(sema, node, cache, cache_stack, diag, edition);
637+
let mut diag_severity =
638+
lint_severity_at(sema, node, &lint_groups(&diag.code, edition), edition);
649639

650640
if let outline_diag_severity @ Some(_) =
651641
find_outline_mod_lint_severity(sema, node, diag, edition)
@@ -698,155 +688,22 @@ fn find_outline_mod_lint_severity(
698688
result
699689
}
700690

701-
#[derive(Debug, Clone, Copy)]
702-
struct SeverityAttr {
703-
severity: Severity,
704-
/// This field counts how far we are from the main node. Bigger values mean more far.
705-
///
706-
/// Note this isn't accurate: there can be gaps between values (created when merging severity maps).
707-
/// The important thing is that if an attr is closer to the main node, it will have smaller value.
708-
///
709-
/// This is necessary even though we take care to never overwrite a value from deeper nesting
710-
/// because of lint groups. For example, in the following code:
711-
/// ```
712-
/// #[warn(non_snake_case)]
713-
/// mod foo {
714-
/// #[allow(nonstandard_style)]
715-
/// mod bar {}
716-
/// }
717-
/// ```
718-
/// We want to not warn on non snake case inside `bar`. If we are traversing this for the first
719-
/// time, everything will be fine, because we will set `diag_severity` on the first matching group
720-
/// and never overwrite it since then. But if `bar` is cached, the cache will contain both
721-
/// `#[warn(non_snake_case)]` and `#[allow(nonstandard_style)]`, and without this field, we have
722-
/// no way of differentiating between the two.
723-
depth: u32,
724-
}
725-
726-
fn fill_lint_attrs(
691+
fn lint_severity_at(
727692
sema: &Semantics<'_, RootDatabase>,
728693
node: &InFile<SyntaxNode>,
729-
cache: &mut FxHashMap<HirFileId, FxHashMap<SmolStr, SeverityAttr>>,
730-
cache_stack: &mut Vec<HirFileId>,
731-
diag: &Diagnostic,
694+
lint_groups: &LintGroups,
732695
edition: Edition,
733696
) -> Option<Severity> {
734-
let mut collected_lint_attrs = FxHashMap::<SmolStr, SeverityAttr>::default();
735-
let mut diag_severity = None;
736-
737-
let mut ancestors = node.value.ancestors().peekable();
738-
let mut depth = 0;
739-
loop {
740-
let ancestor = ancestors.next().expect("we always return from top-level nodes");
741-
depth += 1;
742-
743-
if ancestors.peek().is_none() {
744-
// We don't want to insert too many nodes into cache, but top level nodes (aka. outline modules
745-
// or macro expansions) need to touch the database so they seem like a good fit to cache.
746-
747-
if let Some(cached) = cache.get_mut(&node.file_id) {
748-
// This node (and everything above it) is already cached; the attribute is either here or nowhere.
749-
750-
// Workaround for the borrow checker.
751-
let cached = std::mem::take(cached);
752-
753-
cached.iter().for_each(|(lint, severity)| {
754-
for item in &*cache_stack {
755-
let node_cache_entry = cache
756-
.get_mut(item)
757-
.expect("we always insert cached nodes into the cache map");
758-
let lint_cache_entry = node_cache_entry.entry(lint.clone());
759-
if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry {
760-
// Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
761-
// overwrite top attrs.
762-
lint_cache_entry.insert(SeverityAttr {
763-
severity: severity.severity,
764-
depth: severity.depth + depth,
765-
});
766-
}
767-
}
768-
});
769-
770-
let lints = lint_groups(&diag.code, edition);
771-
let all_matching_groups =
772-
lints.iter().filter_map(|lint_group| cached.get(lint_group));
773-
let cached_severity =
774-
all_matching_groups.min_by_key(|it| it.depth).map(|it| it.severity);
775-
776-
cache.insert(node.file_id, cached);
777-
778-
return diag_severity.or(cached_severity);
779-
}
780-
781-
// Insert this node's descendants' attributes into any outline descendant, but not including this node.
782-
// This must come before inserting this node's own attributes to preserve order.
783-
collected_lint_attrs.drain().for_each(|(lint, severity)| {
784-
if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) {
785-
diag_severity = Some(severity.severity);
786-
}
787-
788-
for item in &*cache_stack {
789-
let node_cache_entry = cache
790-
.get_mut(item)
791-
.expect("we always insert cached nodes into the cache map");
792-
let lint_cache_entry = node_cache_entry.entry(lint.clone());
793-
if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry {
794-
// Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
795-
// overwrite top attrs.
796-
lint_cache_entry.insert(severity);
797-
}
798-
}
799-
});
800-
801-
cache_stack.push(node.file_id);
802-
cache.insert(node.file_id, FxHashMap::default());
803-
804-
if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) {
805-
// Insert this node's attributes into any outline descendant, including this node.
806-
lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| {
807-
if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) {
808-
diag_severity = Some(severity);
809-
}
810-
811-
for item in &*cache_stack {
812-
let node_cache_entry = cache
813-
.get_mut(item)
814-
.expect("we always insert cached nodes into the cache map");
815-
let lint_cache_entry = node_cache_entry.entry(lint.clone());
816-
if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry {
817-
// Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
818-
// overwrite top attrs.
819-
lint_cache_entry.insert(SeverityAttr { severity, depth });
820-
}
821-
}
822-
});
823-
}
824-
825-
let parent_node = sema.find_parent_file(node.file_id);
826-
if let Some(parent_node) = parent_node {
827-
let parent_severity =
828-
fill_lint_attrs(sema, &parent_node, cache, cache_stack, diag, edition);
829-
if diag_severity.is_none() {
830-
diag_severity = parent_severity;
831-
}
832-
}
833-
cache_stack.pop();
834-
return diag_severity;
835-
} else if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) {
836-
lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| {
837-
if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) {
838-
diag_severity = Some(severity);
839-
}
840-
841-
let lint_cache_entry = collected_lint_attrs.entry(lint);
842-
if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry {
843-
// Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
844-
// overwrite top attrs.
845-
lint_cache_entry.insert(SeverityAttr { severity, depth });
846-
}
847-
});
848-
}
849-
}
697+
node.value
698+
.ancestors()
699+
.filter_map(ast::AnyHasAttrs::cast)
700+
.find_map(|ancestor| {
701+
lint_attrs(sema, ancestor, edition)
702+
.find_map(|(lint, severity)| lint_groups.contains(&lint).then_some(severity))
703+
})
704+
.or_else(|| {
705+
lint_severity_at(sema, &sema.find_parent_file(node.file_id)?, lint_groups, edition)
706+
})
850707
}
851708

852709
fn lint_attrs<'a>(
@@ -945,10 +802,6 @@ impl LintGroups {
945802
fn contains(&self, group: &str) -> bool {
946803
self.groups.contains(&group) || (self.inside_warnings && group == "warnings")
947804
}
948-
949-
fn iter(&self) -> impl Iterator<Item = &'static str> {
950-
self.groups.iter().copied().chain(self.inside_warnings.then_some("warnings"))
951-
}
952805
}
953806

954807
fn lint_groups(lint: &DiagnosticCode, edition: Edition) -> LintGroups {

0 commit comments

Comments
 (0)