Get absolute item path from compiler plugin


#1

I have compiler plugin with custom derive directive.
How can I get absolute path to item (not only identifier) for which custom derive directive was used?


#2

You can’t. The compiler doesn’t have that information at the stage that custom derives run.


#3

Ok. Here is my origin task:

I have derive directive for use on traits:

#[derive(Mock)]
trait A { … }

(yeah, I know, derive on traits is strange, but it works), there is also implementation as proc_macro:

#[derive_mock]
trait A { … }

Now, there are traits which are based on another trait:

trait A : Base { … }

Obviously, in order to generate proper implementation I need information about base trait’s methods too. My plan was to remember definitions of all traits derive directive was used on. But I need some key to store and then retrieve these definitions. I wanted to use full paths, but since it’s not available, is there any other way to do it?


#4

I’m not sure what you are trying to do is possible as a custom derive.

Custom derives, and procedural macros in general, work strictly at the token level and are executed after parsing. If you want things like full paths and to know all methods you’ll either need to have defined the traits yourself and hard-code them in (like most custom derives do now), or do something that works with the compiler internals directly.

Inspecting a trait definition as part of one derive, memorising it, then using that to implement things in another custom derive probably won’t work because it requires a very specific execution order and the actual execution order of derives isn’t specified. You’d probably end up not being able to retrieve the stored definitions half the time because those definitions haven’t been visited yet.

There may be other ways to do what you are trying to do though. Could you use a build script that reads your source code and generates code for whatever you are trying to do? This is the process used by cbindgen where it needs to find all definitions for FFI functions so it can generate a C header file.


#5

Obviously, in order to generate proper implementation I need information about base trait’s methods too. My plan was to remember definitions of all traits derive directive was used on.

That sounds like a recipe for either unreproducible builds, or at least, an ugly user experience. (how come I gotta define my traits in a certain order?)

The idea that would come to my mind is:

  • proc-macro-hack. This will let you define an exclamation_point_style! macro. (proc-macro-hack is limited in what sorts of things it can produce, but since you’re producing items you are fine)
  • Require the user to wrap their entire trait hierarchy in a single call.
derive_mocks!{
    trait A { }

    trait B: A { }
}

Given that I haven’t tried this, though, I can offer no comfort with regards to whether or not this idea actually works.