[cfe-dev] Where to put upcoming refcatoring tools
Manuel Klimek
klimek at google.com
Wed Apr 25 13:38:19 PDT 2012
Here's what I would do:
Id("call",
Call(Callee(Function(HasName("::Qt::escape"))),·
HasArgument(0, AnyOf(Id("constructor", ConstructorCall()),
Id("expression", Expression())))))));
Now you get "constructor" bound when there's a conversion going on,
and "expression" bound otherwise.
If "constructor" is bound, replace "call" with
QString::fromUtf8(<constructor-range>), otherwise replace "call" with
(<expression>).toHtmlEscaped();
This works because HasArgument by default looks through parentheses
and implicit casts, and doing what looks like a manual constructor
call there (QString("")) is actually a functional cast.
Tweaking will be necessary if you want to prevent extra parens around
expression.
If the spelling location of <expression> or <constructor> still
doesn't work when you have a macro in there, you'll need to pimp the
getText function to also allow giving you the expansion location.
Cheers,
/Manuel
On Wed, Apr 25, 2012 at 7:13 PM, Manuel Klimek <klimek at google.com> wrote:
> On Wed, Apr 25, 2012 at 6:56 PM, Stephen Kelly <steveire at gmail.com> wrote:
>> Stephen Kelly wrote:
>>
>>> Manuel Klimek wrote:
>>>>
>>>> Does
>>>> Expresssion(AllOf(
>>>> HasType(...),
>>>> Not(ImplicitCast())
>>>> work?
>>>>
>>>
>>> Unfortunately not. The Not(ImplicitCast()) also makes no difference.
>>>
>>> I tried adding a ConstructorCall() in there too, guessing that would match
>>> the implicit ctor calls, but that just excluded all matches from the
>>> result.
>>>
>>> I put a call to Arg->dump() in my MatchCallback implementation. It doesn't
>>> help me, but maybe you can see how I need to define my match with that? My
>>> input is this now:
>>>
>>> Qt::escape("foo");
>>> QString foo("bar");
>>> Qt::escape(foo);
>>> QObject o;
>>> Qt::escape(o.objectName());
>>> Qt::escape(o.property("foo").toByteArray());
>>
>> I found that I could use this to not match the Qt::escape(foo); case.
>>
>> Finder.addMatcher(
>> Id("call",
>> Call(
>> Callee(Function(HasName("::Qt::escape"))),
>> HasArgument(
>> 0,
>> Id("arg", BindTemporaryExpression())
>> )
>> )
>> ),
>> &Callback);
>>
>> I eventually figured out how to limit it to only the case without
>> temporaries:
>>
>> Finder.addMatcher(
>> Id("call",
>> Call(
>> Callee(Function(HasName("::Qt::escape"))),
>> Not(HasArgument(
>> 0,
>> Id("arg", BindTemporaryExpression())
>> )),
>> HasArgument(
>> 0,
>> Id("arg", Expression())
>> )
>> )
>> ),
>> &Callback);
>>
>> I tried many other variations using Not, which I can try to list if you're
>> interested in considering the self-documenting nature of the API.
>>
>> To match the string literal, I used:
>>
>> Finder.addMatcher(
>> Id("call",
>> Call(
>> Callee(Function(HasName("::Qt::escape"))),
>> HasArgument(
>> 0,
>> Id("arg", BindTemporaryExpression())
>> ),
>> Not(hasDescendant(MemberExpression()))
>> )
>> ),
>> &Callback);
>>
>> I could not use this as it gives no results:
>>
>> Finder.addMatcher(
>> Id("call",
>> Call(
>> Callee(Function(HasName("::Qt::escape"))),
>> HasArgument(
>> 0,
>> Id("arg", BindTemporaryExpression())
>> ),
>> ast_matchers::StringLiteral()
>> )
>> ),
>> &Callback);
>>
>>
>> And this one does not build:
>>
>> Finder.addMatcher(
>> Id("call",
>> Call(
>> Callee(Function(HasName("::Qt::escape"))),
>> HasArgument(
>> 0,
>> Id("arg", BindTemporaryExpression())
>> ),
>> Not(hasDescendant(ast_matchers::StringLiteral()))
>> )
>> ),
>> &Callback);
>>
>>
>> Finally this matches the member calls:
>>
>> Finder.addMatcher(
>> Id("call",
>> Call(
>> Callee(Function(HasName("::Qt::escape"))),
>> HasArgument(
>> 0,
>> BindTemporaryExpression()
>> ),
>> hasDescendant(Id("arg", MemberExpression()))
>> )
>> ),
>> &Callback);
>>
>> But I do not get the parentheses or the arguments inside them in the result
>> (if any). I aslo presume this would not match a call of a free function, so
>> I would need more matchers for those cases? It's already getting quite
>> exhaustive and less scalable.
>>
>> It seems either I'm missing something or the tooling is not ready to handle
>> the cases I'm trying to achieve?
>
> Ok, I'm confused by your last example. The way I usually approach this
> is that I write a small cpp file with the stuff I want to match and
> then run clang -ast-dump-xml over it, and look at the resulting AST.
> Then you basically take the matchers that drill through the
> corresponding AST nodes and put them together. I can take a look at
> your specific example tomorrow (I just reread your first explanation
> of what you're trying to do) and come up with an example how I would
> approach this. That might also make up some good documentation :)
>
> Cheers,
> /Manuel
>
>>
>> Thanks,
>>
>> Steve.
>>
>>
>>
>> _______________________________________________
>> cfe-dev mailing list
>> cfe-dev at cs.uiuc.edu
>> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
More information about the cfe-dev
mailing list