How to combine PPCallback with ASTMatcher?

Hello clang developers,

I'm making a clang tool that will transform vec.begin() into
std::begin(vec), and add #include <iterator> if there isn't one.
ASTMatcher is used to match all member call to vec::begin(), and I
need a PPCallback to analyze include files.

I want to create a PPCallback with a ASTMatcher, but find no way to
create a FrontendActionFactory to achive that.

With a FrontendAction class like below:

class MyFrontendAction : public clang::FrontendAction {
public:
    MyFrontendAction(SomeArgs args) { /* ... */ }

    std::unique_ptr<clang::ASTComsumer>
CreateASTConsumer(clang::CompilerInstance& ci, clang::StringRef) {
        auto myCallback = CreateCallback(...);
        ci.getPreprocessor().addPPCallbacks(myCallback);
        auto myMatcher = CreateMatcher(...);
        return myMatcher.newASTConsumer();
    }
};

However, newFrontendActionFactory<MyFrontendAction>() cannot be used
because there is no way to provide constructor arguments; nor can
another overload version be used
because it doesn't pass CompilerInstance to newASTConsumer() function:

template <typename FactoryT>
inline std::unique_ptr<FrontendActionFactory>
newFrontendActionFactory(FactoryT *ConsumerFactory,
SourceFileCallbacks *Callbacks)

Is there any other way so that I can have a parameterized constructor
of FrontendActionFactory and a parameterized interface of
newASTConsumer/createASTConsumer at same time? (Except for
re-implementing a newFrontendActionFactory that match my needs.)

Or am I doing it in the right way?

Any other suggestion? Thanks!

Regards
Xin Huang

Hello clang developers,

I’m making a clang tool that will transform vec.begin() into
std::begin(vec), and add #include if there isn’t one.
ASTMatcher is used to match all member call to vec::begin(), and I
need a PPCallback to analyze include files.

I want to create a PPCallback with a ASTMatcher, but find no way to
create a FrontendActionFactory to achive that.

With a FrontendAction class like below:

class MyFrontendAction : public clang::FrontendAction {
public:
MyFrontendAction(SomeArgs args) { /* … */ }

std::unique_ptrclang::ASTComsumer
CreateASTConsumer(clang::CompilerInstance& ci, clang::StringRef) {
auto myCallback = CreateCallback(…);
ci.getPreprocessor().addPPCallbacks(myCallback);
auto myMatcher = CreateMatcher(…);
return myMatcher.newASTConsumer();
}
};

However, newFrontendActionFactory() cannot be used
because there is no way to provide constructor arguments; nor can
another overload version be used
because it doesn’t pass CompilerInstance to newASTConsumer() function:

template
inline std::unique_ptr
newFrontendActionFactory(FactoryT *ConsumerFactory,
SourceFileCallbacks *Callbacks)

Is there any other way so that I can have a parameterized constructor
of FrontendActionFactory and a parameterized interface of
newASTConsumer/createASTConsumer at same time? (Except for
re-implementing a newFrontendActionFactory that match my needs.)

Implement:
class MFAF : public clang::tooling::FrontendActionFactory {
MFAF(SomeArgs args) : args(args) {}

clang::FrontendAction *create() {
return new MyFrontendAction(args);
}

SomeArgs args;
};

And use that? newFrontendActionFactory is just a convenience function for cases where it makes your life easier - in the end, what it spews out is a FrontendActionFactory anyway…

Cheers,
/Manuel

Thanks Manuel.

I was thinking of adding a vardic template overload of
newFrontendActionFactory to forward all the arguments to the
constructor. But your way is much simpler.

Regards
Xin Huang

Thanks Manuel.

I was thinking of adding a vardic template overload of
newFrontendActionFactory to forward all the arguments to the
constructor. But your way is much simpler.

In some uncommitted patch/work I've got some lambda-based helpers that'll
make it easier to write FrontendActionFactories without so much
boilerplate, fwiw.