Path resolution
Lockjaw need to know the fully qualified path of a type, so they can be compared against each other.
In Rust, all a proc_macro
can see is tokens, which is too early to resolve the type path. When a
Foo
identifier is encountered, it is difficult for the macro to understand whether it is a type
declared in the local module, or a type from somewhere else brought in by a use
declaration. Rust
don't even tell the macro what the local module is.
Base mod
of the file
The first problem is the proc_macro
doesn't even know where the source being compiled is at. The
file!()
and module_path!()
would be a perfect
solution to this, but eager macro expansion is
required for a proc_macro
to be able to utilize it.
proc_macro2::Span::source_file()
also exists, but it is nightly feature and requires procmacro2_semver_exempt
which is contagious.
In the Lockjaw build script this is resolved by looking at the crate's manifest and using
CARGO_CRATE_NAME
/CARGO_PKG_NAME
along with cargo metadata
to figure out the exact path to the source. Path info
is only needed during dependency gathering which is no longer done with proc_macro
, and component generation which is
always ::crate::
and never reference by other part of the code.
mod
structure and use
declarations
A file can still contain nested mod
in it, each importing more symbols with the use
declaration.
For a given token, lockjaw needs to know which mod
it is in, and what symbols are brought into
that scope. This requires parsing the whole file, so we can keep what the span of each mod
is and
what use
are inside it.
syn::parse_file()
sounds like a good fit for
this, however the tokens it produces does not record
proper spans, so we cannot use it
to find the position of mod
.
Lockjaw handles this by parsing the whole file in the build script so it knows which mod
it is in.