ecoricemon/syn-locator

GitHub: ecoricemon/syn-locator

syn-locator 是一个为 Rust syn 语法树提供源代码位置映射的库,帮助开发者在解析后的语法节点上查询其对应的原始源代码字节范围和文本。

Stars: 1 | Forks: 0

# syn-locator [![Crates.io](https://img.shields.io/crates/v/syn-locator.svg)][crates-url] [![CI Status](https://github.com/yuin/goldmark/actions?query=workflow:test](https://static.pigsec.cn/wp-content/uploads/repos/cas/96/96516d7a51f21139fae950e3129296fedeb5ab5f68f6a4dd1d280445b5bfdb15.svg)][ci-url] [![Codecov](https://codecov.io/gh/ecoricemon/syn-locator/graph/badge.svg)][codecov-url] `syn-locator` 在解析 Rust 源代码后,记录 [`syn`](https://crates.io/crates/syn) 语法节点的源代码范围。 当你使用 `syn::parse_str` 或 `syn::parse_file` 解析文件,并且随后需要将诊断、日志、审查或生成的消息指回原始源代码时,这非常有用。 ## 为什么 `syn` 非常适合解析 Rust 语法,但是当你需要面向用户的位置信息时,仅有语法树并不总是足够的。`syn-locator` 会遍历解析后的树,并通过将树的 token 与原始源代码进行匹配来重建字节范围。 一旦定位了树,你可以向任何受支持的节点询问: - 它在原始文件中的字节范围 - 该节点的确切源代码文本 - 简洁的 `path:line: source` 消息 - 借助可选的 `find` feature,找到匹配特定类型的第一个后代节点和源代码片段 ## 快速开始 ``` use syn_locator::{locate, Locate, Location}; let path = "src/example.rs"; let code = " struct User { id: u64, } "; let located = locate::(path, code).unwrap(); let syn::Item::Struct(item_struct) = &located.items[0] else { unreachable!() }; let field = item_struct.fields.iter().next().unwrap(); let ty = &field.ty; assert_eq!(located.code(ty), "u64"); assert_eq!(ty.code(located.locator()), "u64"); assert_eq!(located.location_message(ty), "src/example.rs:3: u64"); let Location { start, end } = located.location(ty); assert_eq!(&code[start..end], "u64"); ``` `Located` 会解引用为 `T`,因此你可以像直接持有解析后的 `syn` 节点一样浏览语法树。 ## 使用已解析的树 如果你已经拥有解析好的语法树,可以使用 `Located::new` 包装它: ``` use syn_locator::Located; let code = "fn answer() -> u32 { 42 }"; let item = syn::parse_str::(code).unwrap(); let located = Located::new(item, "answer.rs", code).unwrap(); assert_eq!(located.code(&located.sig.ident), "answer"); assert_eq!(located.location_message(&located.sig.output), "answer.rs:1: -> u32"); ``` `Located` 同时拥有语法树及其 `Locator`。这很重要,因为位置信息是以语法节点地址为键的;将它们放在一起使得高级 API 成为使用本 crate 最安全的方式。 ## 查找后代 当你想要按节点类型和源代码文本在已定位的树中进行搜索时,请启用 `find` feature。 ``` use syn_locator::{Locate, Located}; let code = "fn push(values: Vec) {}"; let located = syn_locator::locate::("push.rs", code).unwrap(); let ty: &syn::Type = located.find("Vec").unwrap(); assert_eq!(located.code(ty), "Vec"); assert_eq!(ty.location_message(located.locator()), "push.rs:1: Vec"); ``` `find` 返回所请求 Rust 类型中第一个匹配的后代,其后代的定位源代码文本与你传入的片段完全相等。 ## API 概述 - `locate::(path, code)` 将 `code` 解析为 `T` 并返回 `Located`。 - `Located::new(syntax, path, code)` 为已解析的 `syn` 树记录位置信息。 - `Located::syntax()` 返回解析后的语法树。 - `Located::locator()` 返回存储源代码和范围的 `Locator`。 - `Located::location(node)` 返回 `Location { start, end }` 字节范围。 - `Located::code(node)` 返回节点的确切原始源代码文本。 - `Located::location_message(node)` 返回 `path:line: source`。 - 当你持有 `Locator` 时,`Locate` 提供相同的节点级方法。 - `Find` 和 `Located::find` 可通过 `find` feature 使用。 ## 支持的内容 `syn-locator` 为主要的 `syn` 语法族实现了 `Locate`,包括文件、条目(item)、语句、表达式、模式、类型、泛型、属性、路径、字面量、字段、可见性节点、标点符号、运算符和 token。 在实践中,本 crate 面向那些解析 Rust 文件、遍历 `syn` 树并且需要报告所选节点来源的源代码分析工具。 ## 行为与注意事项 位置信息是原始源代码字符串中的字节偏移量。它们不是行或列对;当只需要人类可读的行号时,请使用 `location_message`。 locator 通过按源代码顺序遍历节点并匹配原始代码中的 token 来重建位置。在 token 匹配期间,注释会被替换为空格,因此注释通常不会干扰 token 查找。 因为这是重建而不是编译器的 span 数据,所以结果最适合那些仍然与你要定位的树相匹配的已解析源代码文件。 不要在单独的 `Locator` 中记录位置后修改或移动语法树;除非你确实需要低级 API,否则请首选 `locate` 或 `Located::new`。 ## 测试 运行默认测试套件: ``` cargo test ``` 在启用后代搜索的情况下运行测试: ``` cargo test --features find ``` ## 许可证 根据以下任一许可证授权: - Apache License, Version 2.0 ([LICENSE-APACHE.txt](LICENSE-APACHE.txt)) - MIT license ([LICENSE-MIT.txt](LICENSE-MIT.txt)) 由你选择。
标签:Rust, SOC Prime, 代码定位, 可视化界面, 开发工具, 编译器工具, 网络流量审计, 语法分析, 通知系统