How to get fully qualified path to a type with syntex_syntax?

I am writing a sort of code generator. This program read Rust source code and generates code in another language. I am using syntex_syntax library for parsing and stuck at type tracking. I can get Ty object from various places, but it does't seem to provide fully qualified path to the type. This provides type name just as it appeared on source code, but not as fully qualified form.

For example, let's say we have this code.

mod foo1 {
    mod foo2 {
        struct Bar3 {}
    }
}
use foo1::foo2:::Bar3;
struct Bar4 {
    bar3: Bar3,
}

Ty provides Bar3 only. How can I get foo1::foo2:: part?

1 Like

It seems I have to use syn instead of syntex_syntax.
It's unclear how I can make TokenStream instance from a file.

syn is the modern alternative to syntex. It also compiles a lot faster.

TokenStream implements FromStr, meaning that if you have a String or str you can write string.parse(). That can be given tosyn::parse, so you can write syn::parse(string.parse().unwrap()) to parse anything which implements Synom.


But as for your main problem... you will still have difficulty. The primary uses of syn are:

  • Parsing Rust code
  • Performing lexical transforms
  • (often with the help of quote) Emitting rust code

Its primary use case is in procedural macros, which are usually only given a small bit of input (not an entire library's source code!), and even then are something that run before perfect path resolution is even possible (macro calls in the input need to be expanded before the items they generate can be known, for instance). So I do not believe it provides facilities for path resolution.

You could write something that performs your own path resolution, by making one or more passes with e.g. a Folder that inlines mod foo; files and a Visitor that builds namespace tables. But this seems immensely difficult. Depending on what the source crate contains you would need to reimplement much of the compiler!

(Of course, there are things you could do in the source crate to make this more feasible, such as restricting yourself to absolute use paths, making sure not to re-export a re-export (e.g. use a::b; where a has use c::b), and not using macros that generate items. Then you could perhaps rely on local use statements.)

But I am not sure what to truly recommend as a solution, honestly.

2 Likes

Thanks and I agree.
Maybe I have to use nightly compiler.
If I use nightly compiler, would there be a solution for this?

Before digging in this problem, I thought having a complete AST would be enough to query everything in the source code. Now I know it is not actually.

I think RLS may provide some information for me. I'll try it next.

RLS is not for this. I'll dig into the rustc. Installing nightly is unavoidable...

It's very hard or impossible to do this with syntex_syntax. I failed with it.
Here's another far easier and better approach -- [Solved] How to generate and load save-analysis for a single file without cargo

  • Let compiler to emit analysis data and you can get fully qualified type paths from there.
  • RLS also does this internally.

Now I am looking into compiler drop-in replacement tool. This would be the closest one to what I want if I can make it work...

So far, I'm still failing to get fully qualified type information.

  1. syntax or similar parser based approach fails due to lack of type path resolution.

  2. save-analysis does not store informations for enum variant fields. I am not sure it actually can provide fully qualified path even if it works.

  3. compiler-plugin fails due to lack of type information. HIR tree stores type information as is it appeared in source code, and does not provide fully qualified path even CompileController.after_analysis stage. I'm not sure whether I can get such informations from MIR tree...

  4. RLS. I didn't tried this. save-analysis data lacks enum variant informations, where RLS is depending on.

Overall experience is very frustrating.
I don't want to re-implement compiler type-resolution logic.
I stop this trial here and iIf anyone have any suggestion, please reply here.

Clippy has fully qualified path information. Look into where they are getting it from, I think by calling into librustc. For example see the following code which compares whether the fully qualified path to the trait of some method invocation is equal to std::io::Read.