wat_service 0.7.0

WebAssembly Text Format language service.
Documentation
use crate::{
    LanguageService,
    binder::{SymbolKind, SymbolTable},
    config::LintLevel,
    document::Document,
    helpers, mutability,
};
use line_index::LineIndex;
use lspt::{Diagnostic, DiagnosticSeverity, DiagnosticTag, Union2};

const DIAGNOSTIC_CODE: &str = "needless-mut";

pub fn check(
    service: &LanguageService,
    diagnostics: &mut Vec<Diagnostic>,
    lint_level: LintLevel,
    document: Document,
    line_index: &LineIndex,
    symbol_table: &SymbolTable,
) {
    let severity = match lint_level {
        LintLevel::Allow => return,
        LintLevel::Hint => DiagnosticSeverity::Hint,
        LintLevel::Warn => DiagnosticSeverity::Warning,
        LintLevel::Deny => DiagnosticSeverity::Error,
    };

    let mutation_actions = mutability::get_mutation_actions(service, document);
    diagnostics.extend(
        mutability::get_mutabilities(service, document)
            .iter()
            .filter(|(key, mutability)| {
                mutability.mut_keyword.is_some()
                    && !mutability.cross_module
                    && mutation_actions
                        .values()
                        .filter(|action| action.target.is_some_and(|target| target == **key))
                        .all(|action| action.kind == mutability::MutationActionKind::Get)
            })
            .filter_map(|(key, mutability)| {
                symbol_table.symbols.get(key).zip(mutability.mut_keyword)
            })
            .map(|(symbol, keyword_range)| {
                let kind = match symbol.kind {
                    SymbolKind::GlobalDef => "global",
                    SymbolKind::Type => "array",
                    SymbolKind::FieldDef => "field",
                    _ => unreachable!(),
                };
                Diagnostic {
                    range: helpers::rowan_range_to_lsp_range(line_index, keyword_range),
                    severity: Some(severity),
                    source: Some("wat".into()),
                    code: Some(Union2::B(DIAGNOSTIC_CODE.into())),
                    message: format!(
                        "{kind} `{}` is unnecessarily mutable",
                        symbol.idx.render(service)
                    ),
                    tags: Some(vec![DiagnosticTag::Unnecessary]),
                    ..Default::default()
                }
            }),
    );
}