mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-12-23 08:47:50 +00:00
rename dead code to unused
This commit is contained in:
parent
9fdf82ae08
commit
5e17df077b
11 changed files with 96 additions and 101 deletions
|
|
@ -80,7 +80,7 @@ pub fn query_main(mut cmds: QueryCommands) -> Result<()> {
|
|||
_ => tinymist_query::ColorTheme::Light,
|
||||
},
|
||||
lint: config.lint.when().clone(),
|
||||
dead_code: config.lint.dead_code_config(),
|
||||
unused: config.lint.unused_config(),
|
||||
periscope: None,
|
||||
local_packages: Arc::default(),
|
||||
tokens_caches: Arc::default(),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
//! A linter for Typst.
|
||||
|
||||
mod dead_code;
|
||||
mod unused;
|
||||
|
||||
pub use dead_code::DeadCodeConfig;
|
||||
pub use unused::UnusedConfig;
|
||||
|
||||
/// Hint added to diagnostics for documented exported functions, to mark them as
|
||||
/// likely public API.
|
||||
|
|
@ -49,30 +49,30 @@ pub fn lint_file(
|
|||
known_issues: KnownIssues,
|
||||
) -> LintInfo {
|
||||
let cross_file_refs: FxHashSet<Interned<Decl>> = FxHashSet::default();
|
||||
let dead_code_config = DeadCodeConfig::default();
|
||||
lint_file_with_dead_code_config(
|
||||
let unused_config = UnusedConfig::default();
|
||||
lint_file_with_unused_config(
|
||||
world,
|
||||
ei,
|
||||
ti,
|
||||
known_issues,
|
||||
&cross_file_refs,
|
||||
&dead_code_config,
|
||||
&unused_config,
|
||||
)
|
||||
}
|
||||
|
||||
/// Performs linting check on file with a custom dead-code configuration.
|
||||
pub fn lint_file_with_dead_code_config(
|
||||
/// Performs linting check on file with a custom unused configuration.
|
||||
pub fn lint_file_with_unused_config(
|
||||
world: &LspWorld,
|
||||
ei: &ExprInfo,
|
||||
ti: Arc<TypeInfo>,
|
||||
known_issues: KnownIssues,
|
||||
cross_file_refs: &FxHashSet<Interned<Decl>>,
|
||||
dead_code_config: &DeadCodeConfig,
|
||||
unused_config: &UnusedConfig,
|
||||
) -> LintInfo {
|
||||
let mut diagnostics = Linter::new(world, ei.clone(), ti, known_issues).lint(ei.source.root());
|
||||
|
||||
let dead_code_diags = dead_code::check_dead_code(world, ei, cross_file_refs, dead_code_config);
|
||||
diagnostics.extend(dead_code_diags);
|
||||
let unused_diags = unused::check_unused(world, ei, cross_file_refs, unused_config);
|
||||
diagnostics.extend(unused_diags);
|
||||
|
||||
LintInfo {
|
||||
revision: ei.revision,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
//! Definition collector for dead code analysis.
|
||||
//! Definition collector for unused declaration analysis.
|
||||
|
||||
use rustc_hash::FxHashSet;
|
||||
use tinymist_analysis::{
|
||||
|
|
@ -64,10 +64,10 @@ struct DefinitionCollector<'a> {
|
|||
impl<'a> DefinitionCollector<'a> {
|
||||
fn collect_exports(&mut self) {
|
||||
for (_name, expr) in self.ei.exports.iter() {
|
||||
if let Some(decl) = Self::extract_decl(expr) {
|
||||
if decl.is_def() {
|
||||
self.add_definition(decl, DefScope::Exported);
|
||||
}
|
||||
if let Some(decl) = Self::extract_decl(expr)
|
||||
&& decl.is_def()
|
||||
{
|
||||
self.add_definition(decl, DefScope::Exported);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
//! Diagnostic generator for dead code warnings.
|
||||
//! Diagnostic generator for unused declaration warnings.
|
||||
//!
|
||||
//! This module creates user-friendly diagnostic messages for unused
|
||||
//! definitions, with appropriate hints and severity levels.
|
||||
|
|
@ -81,15 +81,14 @@ pub fn generate_diagnostic(
|
|||
}
|
||||
|
||||
// Add kind-specific hints
|
||||
if let DefKind::Function = def_info.kind {
|
||||
if matches!(def_info.scope, DefScope::Exported)
|
||||
&& ei.docstrings.contains_key(&def_info.decl)
|
||||
{
|
||||
diag = diag.with_hint(DOCUMENTED_EXPORTED_FUNCTION_HINT);
|
||||
diag = diag.with_hint(
|
||||
if let DefKind::Function = def_info.kind
|
||||
&& matches!(def_info.scope, DefScope::Exported)
|
||||
&& ei.docstrings.contains_key(&def_info.decl)
|
||||
{
|
||||
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",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if is_module_like {
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
//! Dead code detection for Typst.
|
||||
//! Unused declaration detection for Typst.
|
||||
|
||||
mod collector;
|
||||
mod diagnostic;
|
||||
|
|
@ -26,9 +26,9 @@ struct ImportUsageInfo {
|
|||
module_used_decls: FxHashSet<Interned<Decl>>,
|
||||
}
|
||||
|
||||
/// Configuration for dead code detection.
|
||||
/// Configuration for unused declaration detection.
|
||||
#[derive(Debug, Clone, Hash)]
|
||||
pub struct DeadCodeConfig {
|
||||
pub struct UnusedConfig {
|
||||
/// Whether to check exported but unused symbols.
|
||||
pub check_exported: bool,
|
||||
/// Whether to check unused function parameters.
|
||||
|
|
@ -37,7 +37,7 @@ pub struct DeadCodeConfig {
|
|||
pub exceptions: Vec<String>,
|
||||
}
|
||||
|
||||
impl Default for DeadCodeConfig {
|
||||
impl Default for UnusedConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
check_exported: false,
|
||||
|
|
@ -47,11 +47,11 @@ impl Default for DeadCodeConfig {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_dead_code(
|
||||
pub fn check_unused(
|
||||
world: &LspWorld,
|
||||
ei: &ExprInfo,
|
||||
cross_file_refs: &FxHashSet<Interned<Decl>>,
|
||||
config: &DeadCodeConfig,
|
||||
config: &UnusedConfig,
|
||||
) -> DiagnosticVec {
|
||||
let mut diagnostics = EcoVec::new();
|
||||
|
||||
|
|
@ -129,10 +129,8 @@ pub fn check_dead_code(
|
|||
_ => !has_references(&def_info.decl),
|
||||
};
|
||||
|
||||
if is_unused {
|
||||
if let Some(diag) = generate_diagnostic(&def_info, world, ei) {
|
||||
diagnostics.push(diag);
|
||||
}
|
||||
if is_unused && let Some(diag) = generate_diagnostic(&def_info, world, ei) {
|
||||
diagnostics.push(diag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -157,26 +155,24 @@ fn compute_import_usage(definitions: &[DefInfo], ei: &ExprInfo) -> ImportUsageIn
|
|||
if matches!(
|
||||
def.decl.as_ref(),
|
||||
Decl::ModuleImport(_) | Decl::ModuleAlias(_)
|
||||
) {
|
||||
if let Some(r) = ei.resolves.get(&def.span) {
|
||||
let fid = r
|
||||
.root
|
||||
.as_ref()
|
||||
.and_then(|expr| expr.file_id())
|
||||
.or_else(|| r.step.as_ref().and_then(|expr| expr.file_id()));
|
||||
if let Some(fid) = fid {
|
||||
module_targets.insert(def.decl.clone(), fid);
|
||||
}
|
||||
) && let Some(r) = ei.resolves.get(&def.span)
|
||||
{
|
||||
let fid = r
|
||||
.root
|
||||
.as_ref()
|
||||
.and_then(|expr| expr.file_id())
|
||||
.or_else(|| r.step.as_ref().and_then(|expr| expr.file_id()));
|
||||
if let Some(fid) = fid {
|
||||
module_targets.insert(def.decl.clone(), fid);
|
||||
}
|
||||
}
|
||||
|
||||
if matches!(def.decl.as_ref(), Decl::ImportAlias(_)) {
|
||||
if let Some(alias_ref) = ei.resolves.get(&def.span) {
|
||||
if let Some(Expr::Decl(step_decl)) = alias_ref.step.as_ref() {
|
||||
alias_links.insert(def.decl.clone(), step_decl.clone());
|
||||
shadowed.insert(step_decl.clone());
|
||||
}
|
||||
}
|
||||
if matches!(def.decl.as_ref(), Decl::ImportAlias(_))
|
||||
&& let Some(alias_ref) = ei.resolves.get(&def.span)
|
||||
&& let Some(Expr::Decl(step_decl)) = alias_ref.step.as_ref()
|
||||
{
|
||||
alias_links.insert(def.decl.clone(), step_decl.clone());
|
||||
shadowed.insert(step_decl.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -195,10 +191,10 @@ fn compute_import_usage(definitions: &[DefInfo], ei: &ExprInfo) -> ImportUsageIn
|
|||
.collect();
|
||||
|
||||
while let Some(alias) = worklist.pop() {
|
||||
if let Some(target) = alias_links.get(&alias) {
|
||||
if used.insert(target.clone()) {
|
||||
worklist.push(target.clone());
|
||||
}
|
||||
if let Some(target) = alias_links.get(&alias)
|
||||
&& used.insert(target.clone())
|
||||
{
|
||||
worklist.push(target.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,7 +305,7 @@ fn collect_used_decls(reference: &RefExpr, used: &mut FxHashSet<Interned<Decl>>)
|
|||
}
|
||||
}
|
||||
|
||||
fn should_skip_definition(def_info: &DefInfo, config: &DeadCodeConfig) -> bool {
|
||||
fn should_skip_definition(def_info: &DefInfo, config: &UnusedConfig) -> bool {
|
||||
if matches!(def_info.scope, DefScope::Exported) && !config.check_exported {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -629,7 +629,7 @@ mod call_info_tests {
|
|||
mod lint_tests {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use tinymist_lint::{DeadCodeConfig, KnownIssues};
|
||||
use tinymist_lint::{KnownIssues, UnusedConfig};
|
||||
|
||||
use crate::tests::*;
|
||||
|
||||
|
|
@ -671,11 +671,11 @@ mod lint_tests {
|
|||
let ti = ctx.type_check(&source);
|
||||
let cross_file_refs = rustc_hash::FxHashSet::default();
|
||||
|
||||
let dead_code_config = DeadCodeConfig {
|
||||
let dead_code_config = UnusedConfig {
|
||||
check_exported: true,
|
||||
..DeadCodeConfig::default()
|
||||
..UnusedConfig::default()
|
||||
};
|
||||
let result = tinymist_lint::lint_file_with_dead_code_config(
|
||||
let result = tinymist_lint::lint_file_with_unused_config(
|
||||
ctx.world(),
|
||||
&ei,
|
||||
ti,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use tinymist_analysis::stats::AllocStats;
|
|||
use tinymist_analysis::syntax::classify_def_loosely;
|
||||
use tinymist_analysis::ty::{BuiltinTy, InsTy, term_value};
|
||||
use tinymist_analysis::{analyze_expr_, analyze_import_};
|
||||
use tinymist_lint::{DeadCodeConfig, KnownIssues, LintInfo};
|
||||
use tinymist_lint::{KnownIssues, LintInfo, UnusedConfig};
|
||||
use tinymist_project::{LspComputeGraph, LspWorld, TaskWhen};
|
||||
use tinymist_std::hash::{FxDashMap, hash128};
|
||||
use tinymist_std::typst::TypstDocument;
|
||||
|
|
@ -83,8 +83,8 @@ pub struct Analysis {
|
|||
pub color_theme: ColorTheme,
|
||||
/// When to trigger the lint.
|
||||
pub lint: TaskWhen,
|
||||
/// Configuration for dead code detection.
|
||||
pub dead_code: DeadCodeConfig,
|
||||
/// Configuration for unused declaration detection.
|
||||
pub unused: UnusedConfig,
|
||||
/// The periscope provider.
|
||||
pub periscope: Option<Arc<dyn PeriscopeProvider + Send + Sync>>,
|
||||
/// The global worker resources for analysis.
|
||||
|
|
@ -839,23 +839,22 @@ impl SharedContext {
|
|||
let ei = self.expr_stage(source);
|
||||
let ti = self.type_check(source);
|
||||
let guard = self.query_stat(source.id(), "lint");
|
||||
self.slot.lint.compute(
|
||||
hash128(&(&ei, &ti, issues, &self.analysis.dead_code)),
|
||||
|_| {
|
||||
self.slot
|
||||
.lint
|
||||
.compute(hash128(&(&ei, &ti, issues, &self.analysis.unused)), |_| {
|
||||
guard.miss();
|
||||
|
||||
let cross_file_refs = self.compute_cross_file_references(source.id(), &ei);
|
||||
|
||||
tinymist_lint::lint_file_with_dead_code_config(
|
||||
tinymist_lint::lint_file_with_unused_config(
|
||||
self.world(),
|
||||
&ei,
|
||||
ti,
|
||||
issues.clone(),
|
||||
&cross_file_refs,
|
||||
&self.analysis.dead_code,
|
||||
&self.analysis.unused,
|
||||
)
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Computes which declarations from the current file are referenced by other files.
|
||||
|
|
|
|||
|
|
@ -980,13 +980,14 @@ pub struct LintFeat {
|
|||
pub enabled: Option<bool>,
|
||||
/// When to trigger the lint checks.
|
||||
pub when: Option<TaskWhen>,
|
||||
/// Dead code detection options.
|
||||
/// Unused declaration detection options.
|
||||
#[serde(
|
||||
default,
|
||||
rename = "deadCode",
|
||||
rename = "unused",
|
||||
alias = "deadCode",
|
||||
deserialize_with = "deserialize_null_default"
|
||||
)]
|
||||
pub dead_code: DeadCodeFeat,
|
||||
pub unused: UnusedFeat,
|
||||
}
|
||||
|
||||
impl LintFeat {
|
||||
|
|
@ -999,26 +1000,26 @@ impl LintFeat {
|
|||
self.when.as_ref().unwrap_or(&TaskWhen::OnSave)
|
||||
}
|
||||
|
||||
/// Gets the dead-code lint configuration derived from `lint.deadCode`.
|
||||
pub fn dead_code_config(&self) -> tinymist_lint::DeadCodeConfig {
|
||||
let mut config = tinymist_lint::DeadCodeConfig::default();
|
||||
if let Some(check_exported) = self.dead_code.check_exported {
|
||||
/// Gets the unused lint configuration derived from `lint.unused`.
|
||||
pub fn unused_config(&self) -> tinymist_lint::UnusedConfig {
|
||||
let mut config = tinymist_lint::UnusedConfig::default();
|
||||
if let Some(check_exported) = self.unused.check_exported {
|
||||
config.check_exported = check_exported;
|
||||
}
|
||||
if let Some(check_params) = self.dead_code.check_params {
|
||||
if let Some(check_params) = self.unused.check_params {
|
||||
config.check_params = check_params;
|
||||
}
|
||||
if let Some(exceptions) = &self.dead_code.exceptions {
|
||||
if let Some(exceptions) = &self.unused.exceptions {
|
||||
config.exceptions = exceptions.clone();
|
||||
}
|
||||
config
|
||||
}
|
||||
}
|
||||
|
||||
/// Dead code detection options under `lint.deadCode`.
|
||||
/// Unused declaration detection options under `lint.unused`.
|
||||
#[derive(Debug, Default, Clone, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct DeadCodeFeat {
|
||||
pub struct UnusedFeat {
|
||||
/// Whether to check module-level (exported) symbols.
|
||||
pub check_exported: Option<bool>,
|
||||
/// Whether to check unused function parameters.
|
||||
|
|
@ -1311,10 +1312,10 @@ mod tests {
|
|||
test_good_config("lint");
|
||||
test_good_config("lint.enabled");
|
||||
test_good_config("lint.when");
|
||||
test_good_config("lint.deadCode");
|
||||
test_good_config("lint.deadCode.checkExported");
|
||||
test_good_config("lint.deadCode.checkParams");
|
||||
test_good_config("lint.deadCode.exceptions");
|
||||
test_good_config("lint.unused");
|
||||
test_good_config("lint.unused.checkExported");
|
||||
test_good_config("lint.unused.checkParams");
|
||||
test_good_config("lint.unused.exceptions");
|
||||
|
||||
test_good_config("preview");
|
||||
test_good_config("preview.browsing");
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ impl ServerState {
|
|||
_ => tinymist_query::ColorTheme::Light,
|
||||
},
|
||||
lint: config.lint.when().clone(),
|
||||
dead_code: config.lint.dead_code_config(),
|
||||
unused: config.lint.unused_config(),
|
||||
periscope: periscope_args.map(|args| {
|
||||
let r = TypstPeriscopeProvider(PeriscopeRenderer::new(args));
|
||||
Arc::new(r) as Arc<dyn PeriscopeProvider + Send + Sync>
|
||||
|
|
|
|||
|
|
@ -454,21 +454,21 @@
|
|||
"%extension.tinymist.config.tinymist.lint.when.string.enum.onType%"
|
||||
]
|
||||
},
|
||||
"tinymist.lint.deadCode.checkExported": {
|
||||
"title": "%extension.tinymist.config.tinymist.lint.deadCode.checkExported.title%",
|
||||
"markdownDescription": "%extension.tinymist.config.tinymist.lint.deadCode.checkExported.desc%",
|
||||
"tinymist.lint.unused.checkExported": {
|
||||
"title": "%extension.tinymist.config.tinymist.lint.unused.checkExported.title%",
|
||||
"markdownDescription": "%extension.tinymist.config.tinymist.lint.unused.checkExported.desc%",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"tinymist.lint.deadCode.checkParams": {
|
||||
"title": "%extension.tinymist.config.tinymist.lint.deadCode.checkParams.title%",
|
||||
"markdownDescription": "%extension.tinymist.config.tinymist.lint.deadCode.checkParams.desc%",
|
||||
"tinymist.lint.unused.checkParams": {
|
||||
"title": "%extension.tinymist.config.tinymist.lint.unused.checkParams.title%",
|
||||
"markdownDescription": "%extension.tinymist.config.tinymist.lint.unused.checkParams.desc%",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"tinymist.lint.deadCode.exceptions": {
|
||||
"title": "%extension.tinymist.config.tinymist.lint.deadCode.exceptions.title%",
|
||||
"markdownDescription": "%extension.tinymist.config.tinymist.lint.deadCode.exceptions.desc%",
|
||||
"tinymist.lint.unused.exceptions": {
|
||||
"title": "%extension.tinymist.config.tinymist.lint.unused.exceptions.title%",
|
||||
"markdownDescription": "%extension.tinymist.config.tinymist.lint.unused.exceptions.desc%",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
|
|
|
|||
|
|
@ -1603,26 +1603,26 @@ zh = "保存文件时执行代码检查"
|
|||
en = "Perform lint checks on type"
|
||||
zh = "标记文件时执行代码检查"
|
||||
|
||||
[extension.tinymist.config.tinymist.lint.deadCode.checkExported.title]
|
||||
[extension.tinymist.config.tinymist.lint.unused.checkExported.title]
|
||||
en = "Check exported symbols"
|
||||
zh = "检查导出符号"
|
||||
|
||||
[extension.tinymist.config.tinymist.lint.deadCode.checkExported.desc]
|
||||
[extension.tinymist.config.tinymist.lint.unused.checkExported.desc]
|
||||
en = "Whether to check module-level (exported) symbols for being unused."
|
||||
zh = "是否检查模块级(导出)符号是否未使用。"
|
||||
|
||||
[extension.tinymist.config.tinymist.lint.deadCode.checkParams.title]
|
||||
[extension.tinymist.config.tinymist.lint.unused.checkParams.title]
|
||||
en = "Check unused parameters"
|
||||
zh = "检查未使用参数"
|
||||
|
||||
[extension.tinymist.config.tinymist.lint.deadCode.checkParams.desc]
|
||||
[extension.tinymist.config.tinymist.lint.unused.checkParams.desc]
|
||||
en = "Whether to check unused function parameters."
|
||||
zh = "是否检查未使用的函数参数。"
|
||||
|
||||
[extension.tinymist.config.tinymist.lint.deadCode.exceptions.title]
|
||||
[extension.tinymist.config.tinymist.lint.unused.exceptions.title]
|
||||
en = "Dead code exceptions"
|
||||
zh = "死代码例外规则"
|
||||
|
||||
[extension.tinymist.config.tinymist.lint.deadCode.exceptions.desc]
|
||||
[extension.tinymist.config.tinymist.lint.unused.exceptions.desc]
|
||||
en = "Glob-like patterns for exceptions (e.g., \"test_*\", \"_*\")."
|
||||
zh = "用于例外的类似 glob 的模式(例如 \"test_*\"、\"_*\")。"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue