for familiarizing myself with writing custom tools for LibTooling I attempted to write a tool for removing (unnecessary) “this->” usage from source code.
Examples:
void inc() {
this->counter++; // becomes: counter++;
}
Now there are a few cases where this would leave to different behaviour when just simply replacing “this->” by “” in source code, which is what I’d like to avoid:
Example:
void foo(bool b) {
this->b = b; // would become: b = b; => self-assignment, BUG
}
void bar() {
int num = this->num(); // would become: int num = num(); => compile-error
}
So, in other words, for a given expression like this->$myid to be replacable by just $myid, the name $myid must not be ambiguous from the context of the expression. (There might be other exceptions, but I’m just assuming this as my rule for now). In all other cases, I’d like to replace “this->” by “” in source code.
Now to the actual question: How to implement this via a clang-tidy tool?
Writing a AST matcher for getting to the expressions referencing this is trivial – something like this:
Now the part I’m struggling with is how to make sure the “member name” is a non-ambiguous identifier from the current context so I can just strip “this->”. How can I find out the accessible declarations (or just the ids) from the context of the expression referencing this? I’m missing API to get the clang::DeclContext, plus looking up declarations accessible from within this context.
I didn't get a lot of replies to my actual question, so let's maybe simplify
it a bit.
My root problem:
Given an instance of clang::Expr: how can I deduce the context of this
expression and get a list of declarations which are accessible from this
context. What API can I use for this?
This sounds trivial, but I didn't figure it out yet. Apparently I'm missing
something obvious here.
Yea, this is really hard currently in clang’s design: the only place at which the lookup information is available is during semantic analysis on clang’s stack
This has been one of the most requested features though, so perhaps we can find a way to allow re-querying some flows of sema (or being able to optionally store some info) for this.
Yea, this is really hard currently in clang's design: the only place at
which the lookup information is available is during semantic analysis on
clang's stack
This has been one of the most requested features though, so perhaps we can
find a way to allow re-querying some flows of sema (or being able to
optionally store some info) for this.
cc'ing Richard for ideas.
It seems relatively straightforward to walk the AST and rebuild the Scope
information that Sema would need to perform an unqualified name lookup from
a specified context. A starting point of a clang::Expr is not sufficient,
however, because that doesn't identify a unique place in the AST; we'd need
to know the path taken to get there. (I'd imagine your AST visitor could
easily accumulate this information when it's looking for places to
transform.)
> Yea, this is really hard currently in clang's design: the only place at
> which the lookup information is available is during semantic analysis on
> clang's stack
>
> This has been one of the most requested features though, so perhaps we can
> find a way to allow re-querying some flows of sema (or being able to
> optionally store some info) for this.
>
> cc'ing Richard for ideas.
It seems relatively straightforward to walk the AST and rebuild the Scope
information that Sema would need to perform an unqualified name lookup from
a specified context. A starting point of a clang::Expr is not sufficient,
however, because that doesn't identify a unique place in the AST; we'd need
to know the path taken to get there. (I'd imagine your AST visitor could
easily accumulate this information when it's looking for places to
transform.)
That means I cannot use AST matchers but have to walk the AST myself and
accumulate information from contexts while walking it? This doesn't sound
straight forward.
Could you point me to code which implements something like this? Or some code
snippet doing so?
> > Yea, this is really hard currently in clang's design: the only place at
> > which the lookup information is available is during semantic analysis
on
> > clang's stack
> >
> > This has been one of the most requested features though, so perhaps we
can
> > find a way to allow re-querying some flows of sema (or being able to
> > optionally store some info) for this.
> >
> > cc'ing Richard for ideas.
>
> It seems relatively straightforward to walk the AST and rebuild the Scope
> information that Sema would need to perform an unqualified name lookup
from
> a specified context. A starting point of a clang::Expr is not sufficient,
> however, because that doesn't identify a unique place in the AST; we'd
need
> to know the path taken to get there. (I'd imagine your AST visitor could
> easily accumulate this information when it's looking for places to
> transform.)
That means I cannot use AST matchers but have to walk the AST myself and
accumulate information from contexts while walking it? This doesn't sound
straight forward.
It's probably reasonable to use the parents map to reconstruct the path in
this case; if you're planning on making a code transformation, you want to
check (for instance) all template instantiations that used that Expr anyway.
Could you point me to code which implements something like this? Or some
code
snippet doing so?
I don't know of any existing code that does anything like this, sorry. As
Manuel says this is something we've had requests for but never actually
provided before.
Note that when Richard says “straight forward” it usually still means “> 1 week to implement for a mortal being”. It’s not trivial.
Unless you absolutely don’t care about things like ADL, in which case you can basically walk up the DeclContexts looking for a symbol with the name - i’m not sure whether you’d need special casing for parameters (Richard?)