wat_service 0.10.2

WebAssembly Text Format language service.
Documentation
use crate::{binder::SymbolKey, document::Document};
use rustc_hash::FxHashMap;
use wat_syntax::SyntaxKind;

#[salsa::tracked(returns(ref))]
pub(crate) fn get_deprecation(db: &dyn salsa::Database, document: Document) -> FxHashMap<SymbolKey, Option<String>> {
    let root = document.root_tree(db);
    root.children()
        .flat_map(|module| module.children())
        .filter(|node| {
            matches!(
                node.kind(),
                SyntaxKind::MODULE_FIELD_FUNC
                    | SyntaxKind::MODULE_FIELD_GLOBAL
                    | SyntaxKind::MODULE_FIELD_MEMORY
                    | SyntaxKind::MODULE_FIELD_TABLE
                    | SyntaxKind::MODULE_FIELD_TAG
                    | SyntaxKind::TYPE_DEF
                    | SyntaxKind::MODULE_FIELD_IMPORT
                    | SyntaxKind::MODULE_FIELD_DATA
                    | SyntaxKind::MODULE_FIELD_ELEM
            )
        })
        .chain(
            root.children()
                .flat_map(|module| module.children())
                .filter(|node| node.kind() == SyntaxKind::REC_TYPE)
                .flat_map(|node| node.children()),
        )
        .filter_map(|node| {
            let key = if node.kind() == SyntaxKind::MODULE_FIELD_IMPORT {
                node.amber()
                    .children_by_kind(|kind| {
                        matches!(
                            kind,
                            SyntaxKind::EXTERN_TYPE_FUNC
                                | SyntaxKind::EXTERN_TYPE_GLOBAL
                                | SyntaxKind::EXTERN_TYPE_MEMORY
                                | SyntaxKind::EXTERN_TYPE_TABLE
                                | SyntaxKind::EXTERN_TYPE_TAG
                        )
                    })
                    .next()?
                    .to_ptr()
                    .into()
            } else {
                SymbolKey::new(&node)
            };
            node.prev_consecutive_tokens()
                .take_while(|token| token.kind().is_trivia())
                .find(|token| {
                    token.kind() == SyntaxKind::ANNOT_START
                        && token
                            .text()
                            .strip_prefix("(@")
                            .map(|s| s.strip_prefix('"').and_then(|s| s.strip_suffix('"')).unwrap_or(s))
                            .is_some_and(|name| name == "deprecated")
                })
                .map(|annot_start| {
                    let reason = annot_start
                        .next_consecutive_tokens()
                        .take_while(|token| token.kind().is_trivia())
                        .find_map(|token| {
                            if token.kind() == SyntaxKind::ANNOT_ELEM {
                                token
                                    .text()
                                    .strip_prefix('"')
                                    .and_then(|s| s.strip_suffix('"'))
                                    .map(String::from)
                            } else {
                                None
                            }
                        });
                    (key, reason)
                })
        })
        .collect()
}