The fundamental problem with using source text as an intermediate representation is that you lose hygiene (as you note), which is one of the prime benefits of the Rust macro system. I don’t think there is any way to preserve hygiene in a source text representation (you could rename of course, but then you must ensure the source text is not changed by the user).
On the other hand if the tools are smart enough, then working with macros should really be no problem. They are simply a program transformation, just like the rest of the compiler transforms source code to binary (to some extent debug info can just take this into account, just like the rest of compilation). Which is not to say it is easy, but it is totally possible, even with procedural macros (see Dr Racket for an example of a tool with great support for macros).
In the compiler, we have expansion traces embedded in the spans for source code to handle this sort of thing which the compiler and some tools make use of (you could consider this the metadata to describe the effects of the macro, although it is not exported in any form at the moment). Over the winter, a student had a project to make code search work with macros and it works really well (I hope to have a demo soon, unfortunately there are some unrelated memory issues with the tool at the moment).
So, in terms of solving the problem in Intelli J, you have two options: either make the parser macro aware, or interact with the compiler. I prefer the second approach (but I’m obviously biased). The first approach is certainly feasible, but not easy and I can’t think of an 80/20 solution that would get you wins. I think it will only get worse too, because in the future we plan to tie name resolution much more closely to macro expansion. On the other hand, if you do manage to implement it all (and I’m very impressed with what you’ve done so far) then we’d be pretty close to having a second Rust compiler, which would be really great.
We do want incremental compilation anyway (compilation times are a real sore spot for Rust at the moment), and the implementation is well under way. The rest is also hard, but hopefully not too hard!