wat_service 0.5.1

WebAssembly Text Format language service.
Documentation
use crate::{
    binder::{SymbolKind, SymbolTable},
    config::LintLevel,
    helpers,
    mutability::{MutabilitiesCtx, MutationActionKind},
    uri::InternUri,
    LanguageService,
};
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,
    uri: InternUri,
    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 = service.mutation_actions(uri);
    diagnostics.extend(
        service
            .mutabilities(uri)
            .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 == MutationActionKind::Get)
            })
            .filter_map(|(key, mutability)| {
                symbol_table
                    .symbols
                    .iter()
                    .find(|symbol| symbol.key == *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()
                }
            }),
    );
}