wat_service 0.3.0

WebAssembly Text Format language service.
Documentation
use crate::{
    binder::{SymbolKey, SymbolTable},
    helpers,
    uri::{InternUri, UrisCtx},
    LanguageService,
};
use line_index::LineIndex;
use lsp_types::{
    Diagnostic, DiagnosticRelatedInformation, DiagnosticSeverity, Location, NumberOrString,
};
use rowan::ast::{support, AstNode};
use wat_syntax::{
    ast::{GlobalType, PlainInstr},
    SyntaxNode,
};

const DIAGNOSTIC_CODE: &str = "global-mutation";

pub fn check(
    service: &LanguageService,
    diags: &mut Vec<Diagnostic>,
    uri: InternUri,
    line_index: &LineIndex,
    root: &SyntaxNode,
    symbol_table: &SymbolTable,
    node: &SyntaxNode,
) {
    let Some(instr) = PlainInstr::cast(node.clone()) else {
        return;
    };
    match instr.instr_name() {
        Some(name) if name.text() == "global.set" => {}
        _ => return,
    }
    diags.extend(instr.immediates().filter_map(|immediate| {
        let defs = symbol_table.find_defs(SymbolKey::new(immediate.syntax()))?;
        let related_information = defs
            .filter_map(|def| support::child::<GlobalType>(&def.key.to_node(root)))
            .filter(|global_type| global_type.mut_keyword().is_none())
            .map(|global_type| DiagnosticRelatedInformation {
                location: Location {
                    uri: service.lookup_uri(uri),
                    range: helpers::rowan_range_to_lsp_range(
                        line_index,
                        global_type.syntax().text_range(),
                    ),
                },
                message: "immutable global type".into(),
            })
            .collect::<Vec<_>>();
        if related_information.is_empty() {
            None
        } else {
            Some(Diagnostic {
                range: helpers::rowan_range_to_lsp_range(
                    line_index,
                    immediate.syntax().text_range(),
                ),
                severity: Some(DiagnosticSeverity::ERROR),
                source: Some("wat".into()),
                code: Some(NumberOrString::String(DIAGNOSTIC_CODE.into())),
                message: "mutating an immutable global is not allowed".into(),
                related_information: Some(related_information),
                ..Default::default()
            })
        }
    }));
}