What kind of module paths do you want to support? Only those starting with crate or also those starting with super or self? How about paths to external crates? Also, do you need to support platforms like Windows where ./src/module/xx.rs is not a valid path?
I just want to parse the contents of a module with its path,
crate:module:xxx
self:module:xxx
super:module:xxx
:module:xxx
for example, this code won't work, because it requires an OS path and not a Path with module tree format :
let syntax: syn::File = syn::parse_file("crate:module:xxx").unwrap();
I want to use syn::parse with a path like "{crate|self|super}:module:xxx".
the aim is to create a macro that receives a list of modules as a parameter, and scans them to list all the functions contained in each module.
is there a way to parse the module with its path in Rust format, or if not, convert the path to absolute format (OS folders) and then use the function syn::parse_file ?
I don't know your exact use case, but I don't think there's a general solution, and you- probably have to implement it yourself for your specific need.
generally, module paths don't have a definitive map to file paths, some examples:
// lib.rs
#[path = "generated/foobar.rs"]
mod foo;
pub use foo as foo2;
mod bar {
#[path = "not-foo.rs"]
pub mod foo;
pub use crate::foo as foo2;
mod baz {
pub use super::foo;
}
pub use self::baz as baz2;
}
pub use crate::bar as bar2;
it is non trvial to replicate the behavior of rust-anaylzer, as rust-analyzer has the full context around the module path: e.g. it parses the entire code from the crate root module, in addition to information about all the depencencies via cargo metadata,it compiles and runs build.rs, it can expands macros (both declarative and procedural, which needs to run proc-macro crates in a host process), and it even understands semantics of the code to certain extent (not as much as the type checker, but still enough to provide useful code actions). in other words, it basically IS a compiler front end, just less capable (and maybe incorrect sometimes) than e.g. rustc.
by the way, are you writing an developer tool, or a user library? if you are writing a "reflection" library, you might just use the information provided by the compiler. for example, your library can provide a attribute-like procedural macro (let's call it reflect), and the user must annotate their code, something like:
#[reflect(functions, constants, sub_modules)]
mod foo {
mod bar {
#[reflect(fields)]
struct Foo {
x: i32,
}
}
}
if you are writing a tool, did you consider use a clippy lint?