use crate::linter::diagnostic::{Diagnostic, Severity};
use crate::linter::rules::{Example, Rule, RuleContext};
use crate::semantic::{BindingKind, LoadKind};
pub struct UnusedImport;
impl Rule for UnusedImport {
fn id(&self) -> &'static str {
"unused-import"
}
fn description(&self) -> &'static str {
"Flag an explicitly imported name that is never used: `import X`, \
`import X as Y`, and the colon-item forms `using X: a` / `import X: a`. \
The whole-module `using X` form is exempt, since it attaches exports \
that resolve elsewhere. A qualified use (`X.f`) or a re-`export` counts \
as a use."
}
fn examples(&self) -> &'static [Example] {
&[Example {
caption: "`sortperm` is imported but never referenced:",
source: "using Base: sortperm, sum\n\nprintln(sum([1, 2, 3]))\n",
}]
}
fn check_file(&self, ctx: &RuleContext<'_>, sink: &mut Vec<Diagnostic>) {
for binding in ctx.model.bindings() {
if binding.read || binding.kind != BindingKind::Import {
continue;
}
if is_whole_module_using(ctx, binding.def_range) {
continue;
}
sink.push(Diagnostic {
path: None,
start: binding.def_range.start().into(),
end: binding.def_range.end().into(),
rule: self.id().to_string(),
severity: Severity::Warning,
message: format!("`{}` is imported but never used", binding.name),
fixes: Vec::new(),
suppressed: false,
});
}
}
}
fn is_whole_module_using(ctx: &RuleContext<'_>, def: rowan::TextRange) -> bool {
ctx.model.module_loads().iter().any(|load| {
load.kind == LoadKind::Using && load.items.is_none() && load.range.contains_range(def)
})
}