mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-12-23 08:47:50 +00:00
fix(lint): refine dead-code exported handling
- Treat module-level exported symbols as exported when configured - De-duplicate decl diagnostics across scopes - Replace docstring suppression with a softer hint
This commit is contained in:
parent
8d0361735e
commit
9d0308febc
3 changed files with 37 additions and 35 deletions
|
|
@ -68,20 +68,31 @@ pub fn check_dead_code(
|
|||
module_used_decls,
|
||||
} = compute_import_usage(&definitions, ei);
|
||||
|
||||
let mut seen_module_aliases = HashSet::new();
|
||||
let mut seen_decls = HashSet::new();
|
||||
|
||||
for def_info in definitions {
|
||||
if matches!(def_info.decl.as_ref(), Decl::ModuleAlias(_))
|
||||
&& !seen_module_aliases.insert(def_info.decl.clone())
|
||||
let def_info = if config.check_exported
|
||||
&& matches!(def_info.scope, DefScope::File)
|
||||
&& is_exported_symbol_candidate(def_info.decl.as_ref())
|
||||
&& ei.is_exported(&def_info.decl)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DefInfo {
|
||||
scope: DefScope::Exported,
|
||||
..def_info
|
||||
}
|
||||
} else {
|
||||
def_info
|
||||
};
|
||||
|
||||
if shadowed.contains(&def_info.decl) {
|
||||
continue;
|
||||
}
|
||||
if should_skip_definition(&def_info, config) {
|
||||
continue;
|
||||
}
|
||||
if !seen_decls.insert(def_info.decl.clone()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_unused = match def_info.decl.as_ref() {
|
||||
Decl::Import(_) | Decl::ImportAlias(_) => !used.contains(&def_info.decl),
|
||||
|
|
@ -213,6 +224,13 @@ fn compute_import_usage(definitions: &[DefInfo], ei: &ExprInfo) -> ImportUsageIn
|
|||
}
|
||||
}
|
||||
|
||||
fn is_exported_symbol_candidate(decl: &Decl) -> bool {
|
||||
matches!(
|
||||
decl,
|
||||
Decl::Func(_) | Decl::Var(_) | Decl::Module(_) | Decl::Closure(_)
|
||||
)
|
||||
}
|
||||
|
||||
fn is_wildcard_module_import_decl(ei: &ExprInfo, decl: &Interned<Decl>) -> bool {
|
||||
let span = decl.span();
|
||||
if span.is_detached() {
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@
|
|||
use tinymist_analysis::syntax::{Decl, DefKind, ExprInfo};
|
||||
use tinymist_project::LspWorld;
|
||||
use typst::diag::{SourceDiagnostic, eco_format};
|
||||
use typst::syntax::ast::AstNode;
|
||||
use typst::syntax::{LinkedNode, Span, ast};
|
||||
|
||||
use super::collector::{DefInfo, DefScope};
|
||||
|
||||
use crate::DOCUMENTED_EXPORTED_FUNCTION_HINT;
|
||||
|
||||
/// Generates a diagnostic for an unused definition.
|
||||
///
|
||||
/// Creates a warning with contextual information about the unused symbol,
|
||||
|
|
@ -51,14 +51,12 @@ pub fn generate_diagnostic(
|
|||
}
|
||||
|
||||
// Create the base diagnostic
|
||||
let highlight_span = binding_span(def_info, ei).unwrap_or(def_info.span);
|
||||
|
||||
let mut diag = if is_module_import {
|
||||
SourceDiagnostic::warning(highlight_span, eco_format!("unused module import"))
|
||||
SourceDiagnostic::warning(def_info.span, eco_format!("unused module import"))
|
||||
} else if is_import_item {
|
||||
SourceDiagnostic::warning(highlight_span, eco_format!("unused import: `{name}`"))
|
||||
SourceDiagnostic::warning(def_info.span, eco_format!("unused import: `{name}`"))
|
||||
} else {
|
||||
SourceDiagnostic::warning(highlight_span, eco_format!("unused {kind_str}: `{name}`"))
|
||||
SourceDiagnostic::warning(def_info.span, eco_format!("unused {kind_str}: `{name}`"))
|
||||
};
|
||||
|
||||
// Add helpful hints based on the scope and kind
|
||||
|
|
@ -84,12 +82,13 @@ pub fn generate_diagnostic(
|
|||
|
||||
// Add kind-specific hints
|
||||
if let DefKind::Function = def_info.kind {
|
||||
// Check if there's a docstring - documented functions might be intentional API
|
||||
if matches!(def_info.scope, DefScope::Exported)
|
||||
&& ei.docstrings.contains_key(&def_info.decl)
|
||||
{
|
||||
// Reduce severity for documented functions (they might be public API)
|
||||
return None;
|
||||
diag = diag.with_hint(DOCUMENTED_EXPORTED_FUNCTION_HINT);
|
||||
diag = diag.with_hint(
|
||||
"if this is intended public API, you can ignore this diagnostic; otherwise consider removing it",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,23 +98,3 @@ pub fn generate_diagnostic(
|
|||
|
||||
Some(diag)
|
||||
}
|
||||
|
||||
fn binding_span(def_info: &DefInfo, ei: &ExprInfo) -> Option<Span> {
|
||||
if !matches!(def_info.kind, DefKind::Variable | DefKind::Constant) {
|
||||
return None;
|
||||
}
|
||||
if !matches!(def_info.scope, DefScope::File | DefScope::Local) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let node = LinkedNode::new(ei.source.root()).find(def_info.span)?;
|
||||
let mut current = Some(node);
|
||||
while let Some(node) = current {
|
||||
if let Some(binding) = node.cast::<ast::LetBinding>() {
|
||||
return Some(binding.span());
|
||||
}
|
||||
current = node.parent().cloned();
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ mod dead_code;
|
|||
|
||||
pub use dead_code::DeadCodeConfig;
|
||||
|
||||
/// Hint added to diagnostics for documented exported functions, to mark them as
|
||||
/// likely public API.
|
||||
pub const DOCUMENTED_EXPORTED_FUNCTION_HINT: &str =
|
||||
"this function is exported and documented; it may be part of the public API";
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use tinymist_analysis::{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue