Skip to content

Commit 7d8f830

Browse files
authored
[move-compiler] Added basic stats about suppressed linters (#13800)
## Description This PR adds basic stats about suppressed linters in user code. ## Test Plan All existing tests must pass plus manually tested that the correct stats get printed. --- If your changes are not user-facing and not a breaking change, you can skip the following section. Otherwise, please indicate what changed, and then add to the Release Notes section as highlighted during the release process. ### Type of Change (Check all that apply) - [ ] protocol change - [x] user-visible impact - [ ] breaking change for a client SDKs - [ ] breaking change for FNs (FN binary must upgrade) - [ ] breaking change for validators or node operators (must upgrade binaries) - [ ] breaking change for on-chain data layout - [ ] necessitate either a data wipe or data migration ### Release notes When linter warnings in user code are suppressed, basic statistics about suppressed warnings (number of suppresed warnings and number of suppressed warning categories) will be printed.
1 parent 0bbd3b0 commit 7d8f830

File tree

4 files changed

+70
-21
lines changed

4 files changed

+70
-21
lines changed

move-compiler/src/diagnostics/mod.rs

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,17 @@ pub struct Diagnostic {
5757
#[derive(PartialEq, Eq, Hash, Clone, Debug, Default)]
5858
pub struct Diagnostics {
5959
diagnostics: Vec<Diagnostic>,
60+
// diagnostics filtered in source code
61+
filtered_source_diagnostics: Vec<Diagnostic>,
6062
severity_count: BTreeMap<Severity, usize>,
6163
}
6264

6365
#[derive(PartialEq, Eq, Clone, Debug)]
6466
/// Used to filter out diagnostics, specifically used for warning suppression
65-
pub struct WarningFilters(BTreeMap<ExternalPrefix, UnprefixedWarningFilters>);
67+
pub struct WarningFilters {
68+
filters: BTreeMap<ExternalPrefix, UnprefixedWarningFilters>,
69+
for_dependency: bool, // if false, the filters are used for source code
70+
}
6671

6772
#[derive(PartialEq, Eq, Clone, Debug)]
6873
/// Filters split by category and code
@@ -214,6 +219,7 @@ impl Diagnostics {
214219
pub fn new() -> Self {
215220
Self {
216221
diagnostics: vec![],
222+
filtered_source_diagnostics: vec![],
217223
severity_count: BTreeMap::new(),
218224
}
219225
}
@@ -245,9 +251,14 @@ impl Diagnostics {
245251
}
246252
}
247253

254+
pub fn add_source_filtered(&mut self, diag: Diagnostic) {
255+
self.filtered_source_diagnostics.push(diag)
256+
}
257+
248258
pub fn extend(&mut self, other: Self) {
249259
let Self {
250260
diagnostics,
261+
filtered_source_diagnostics: _,
251262
severity_count,
252263
} = other;
253264
for (sev, count) in severity_count {
@@ -294,6 +305,21 @@ impl Diagnostics {
294305
.iter()
295306
.any(|d| d.info.external_prefix() == Some(prefix))
296307
}
308+
309+
/// Returns the number of diags filtered in source (user) code (an not in the dependencies) that
310+
/// have a given prefix (first value returned) and how many different categories of diags were
311+
/// filtered.
312+
pub fn filtered_source_diags_with_prefix(&self, prefix: &str) -> (usize, usize) {
313+
let mut filtered_diags_num = 0;
314+
let mut filtered_categories = HashSet::new();
315+
self.filtered_source_diagnostics.iter().for_each(|d| {
316+
if d.info.external_prefix() == Some(prefix) {
317+
filtered_diags_num += 1;
318+
filtered_categories.insert(d.info.category());
319+
}
320+
});
321+
(filtered_diags_num, filtered_categories.len())
322+
}
297323
}
298324

299325
impl Diagnostic {
@@ -379,8 +405,18 @@ macro_rules! diag {
379405
}
380406

381407
impl WarningFilters {
382-
pub fn new() -> Self {
383-
Self(BTreeMap::new())
408+
pub fn new_for_source() -> Self {
409+
Self {
410+
filters: BTreeMap::new(),
411+
for_dependency: false,
412+
}
413+
}
414+
415+
pub fn new_for_dependency() -> Self {
416+
Self {
417+
filters: BTreeMap::new(),
418+
for_dependency: true,
419+
}
384420
}
385421

386422
pub fn is_filtered(&self, diag: &Diagnostic) -> bool {
@@ -389,24 +425,28 @@ impl WarningFilters {
389425

390426
fn is_filtered_by_info(&self, info: &DiagnosticInfo) -> bool {
391427
let prefix = info.external_prefix();
392-
self.0
428+
self.filters
393429
.get(&prefix)
394430
.is_some_and(|filters| filters.is_filtered_by_info(info))
395431
}
396432

397433
pub fn union(&mut self, other: &Self) {
398-
for (prefix, filters) in &other.0 {
399-
self.0
434+
for (prefix, filters) in &other.filters {
435+
self.filters
400436
.entry(*prefix)
401437
.or_insert_with(UnprefixedWarningFilters::new)
402438
.union(filters);
403439
}
440+
// if there is a dependency code filter on the stack, it means we are filtering dependent
441+
// code and this information must be preserved when stacking up additional filters (which
442+
// involves union of the current filter with the new one)
443+
self.for_dependency = self.for_dependency || other.for_dependency;
404444
}
405445

406446
pub fn add(&mut self, filter: WarningFilter) {
407447
let (prefix, category, code, name) = match filter {
408448
WarningFilter::All(prefix) => {
409-
self.0.insert(prefix, UnprefixedWarningFilters::All);
449+
self.filters.insert(prefix, UnprefixedWarningFilters::All);
410450
return;
411451
}
412452
WarningFilter::Category {
@@ -421,17 +461,24 @@ impl WarningFilters {
421461
name,
422462
} => (prefix, category, Some(code), name),
423463
};
424-
self.0
464+
self.filters
425465
.entry(prefix)
426466
.or_insert(UnprefixedWarningFilters::Empty)
427467
.add(category, code, name)
428468
}
429469

430470
pub fn unused_warnings_filter_for_test() -> Self {
431-
Self(BTreeMap::from([(
432-
None,
433-
UnprefixedWarningFilters::unused_warnings_filter_for_test(),
434-
)]))
471+
Self {
472+
filters: BTreeMap::from([(
473+
None,
474+
UnprefixedWarningFilters::unused_warnings_filter_for_test(),
475+
)]),
476+
for_dependency: false,
477+
}
478+
}
479+
480+
pub fn for_dependency(&self) -> bool {
481+
self.for_dependency
435482
}
436483
}
437484

@@ -561,6 +608,7 @@ impl From<Vec<Diagnostic>> for Diagnostics {
561608
}
562609
Self {
563610
diagnostics,
611+
filtered_source_diagnostics: vec![],
564612
severity_count,
565613
}
566614
}
@@ -574,7 +622,7 @@ impl From<Option<Diagnostic>> for Diagnostics {
574622

575623
impl AstDebug for WarningFilters {
576624
fn ast_debug(&self, w: &mut crate::shared::ast_debug::AstWriter) {
577-
for (prefix, filters) in &self.0 {
625+
for (prefix, filters) in &self.filters {
578626
let prefix_str = prefix.unwrap_or(WARNING_FILTER_ATTR);
579627
match filters {
580628
UnprefixedWarningFilters::All => w.write(&format!(

move-compiler/src/expansion/translate.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl<'env, 'map> Context<'env, 'map> {
5151
compilation_env: &'env mut CompilationEnv,
5252
module_members: UniqueMap<ModuleIdent, ModuleMembers>,
5353
) -> Self {
54-
let mut all_filter_alls = WarningFilters::new();
54+
let mut all_filter_alls = WarningFilters::new_for_dependency();
5555
for allow in compilation_env.filter_attributes() {
5656
for f in compilation_env.filter_from_str(FILTER_ALL, *allow) {
5757
all_filter_alls.add(f);
@@ -839,7 +839,7 @@ fn warning_filter(
839839
) -> WarningFilters {
840840
use crate::diagnostics::codes::Category;
841841
use known_attributes::DiagnosticAttribute;
842-
let mut warning_filters = WarningFilters::new();
842+
let mut warning_filters = WarningFilters::new_for_source();
843843
let filter_attribute_names = context.env.filter_attributes().clone();
844844
for allow in filter_attribute_names {
845845
let Some(attr) = attributes.get_(&allow) else {

move-compiler/src/shared/mod.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -364,17 +364,15 @@ impl CompilationEnv {
364364
}
365365

366366
pub fn add_diag(&mut self, mut diag: Diagnostic) {
367-
let is_filtered = self
368-
.warning_filter
369-
.last()
367+
let filter = self.warning_filter.last();
368+
let is_filtered = filter
370369
.map(|filter| filter.is_filtered(&diag))
371370
.unwrap_or(false);
372371
if !is_filtered {
373372
// add help to suppress warning, if applicable
374373
// TODO do we want a centralized place for tips like this?
375374
if diag.info().severity() == Severity::Warning {
376375
if let Some(filter_info) = self.known_filter_names.get(&diag.info().id()) {
377-
// if let Some(filter_attr_name) =
378376
let help = format!(
379377
"This warning can be suppressed with '#[{}({})]' \
380378
applied to the 'module' or module member ('const', 'fun', or 'struct')",
@@ -385,6 +383,9 @@ impl CompilationEnv {
385383
}
386384
}
387385
self.diags.add(diag)
386+
} else if !filter.unwrap().for_dependency() {
387+
// unwrap above is safe as the filter has been used (thus it must exist)
388+
self.diags.add_source_filtered(diag)
388389
}
389390
}
390391

@@ -692,7 +693,7 @@ impl Default for PackageConfig {
692693
fn default() -> Self {
693694
Self {
694695
is_dependency: false,
695-
warning_filter: WarningFilters::new(),
696+
warning_filter: WarningFilters::new_for_source(),
696697
flavor: Flavor::default(),
697698
edition: Edition::default(),
698699
}

tools/move-package/src/resolution/resolution_graph.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,7 +460,7 @@ impl Package {
460460
.edition
461461
.or(config.default_edition)
462462
.unwrap_or_default(),
463-
warning_filter: WarningFilters::new(),
463+
warning_filter: WarningFilters::new_for_source(),
464464
}
465465
}
466466
}

0 commit comments

Comments
 (0)