问题
Base RecursiveASTVisitor
If input file is test.cpp it can run to VisitRecordDecl. When I modify file name to test.h it can't .
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/Stmt.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
#include <iostream>
#include <fstream>
#include <string>
using namespace clang;
using namespace std;
using namespace llvm;
using namespace clang::tooling;
using namespace llvm;
static llvm::cl::OptionCategory MyToolCategory("find-class option");
static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
static cl::opt<bool>
OutPutFolder("o", cl::desc("OutPut folder,which need"), cl::cat(MyToolCategory));
namespace clang
{
class FindClassVisitor : public RecursiveASTVisitor<FindClassVisitor>
{
public:
explicit FindClassVisitor(ASTContext &Context)
: Context(Context){}
bool VisitRecordDecl(clang::RecordDecl *D) ///测试用
{
D->dump();
return true;
}
private:
ASTContext &Context;
};
class FindClassConsumer : public ASTConsumer
{
public:
explicit FindClassConsumer(ASTContext &Context)
: visitor(Context){}
virtual void HandleTranslationUnit(clang::ASTContext &Context)
{
visitor.TraverseDecl(Context.getTranslationUnitDecl());
}
private:
FindClassVisitor visitor;
};
class FindClassAction : public clang::ASTFrontendAction
{
public:
virtual std::unique_ptr<clang::ASTConsumer> CreateASTConsumer(
clang::CompilerInstance &compiler, llvm::StringRef InFile )
{
return std::unique_ptr<clang::ASTConsumer>(new FindClassConsumer(compiler.getASTContext()));
}
std::unique_ptr<ASTConsumer> newASTConsumer(clang::CompilerInstance &CI, StringRef InFile)
{
return std::unique_ptr<clang::ASTConsumer>(new FindClassConsumer(CI.getASTContext()));
}
};
}
// not understand just use
template<>
inline std::unique_ptr<FrontendActionFactory> clang::tooling::newFrontendActionFactory(
clang::FindClassAction *ConsumerFactory, SourceFileCallbacks *Callbacks) {
class FrontendActionFactoryAdapter : public FrontendActionFactory {
public:
explicit FrontendActionFactoryAdapter(clang::FindClassAction *ConsumerFactory,
SourceFileCallbacks *Callbacks)
: ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {}
std::unique_ptr<FrontendAction>create() override {
return std::unique_ptr<FrontendAction>(
new ConsumerFactoryAdaptor(ConsumerFactory, Callbacks));
}
private:
class ConsumerFactoryAdaptor : public clang::ASTFrontendAction {
public:
ConsumerFactoryAdaptor(clang::FindClassAction *ConsumerFactory,
SourceFileCallbacks *Callbacks)
: ConsumerFactory(ConsumerFactory), Callbacks(Callbacks) {}
std::unique_ptr<clang::ASTConsumer>
CreateASTConsumer(clang::CompilerInstance &CI, StringRef InFile) override {
return ConsumerFactory->newASTConsumer(CI, InFile);
}
protected:
void EndSourceFileAction() override {
if (Callbacks)
Callbacks->handleEndSource();
clang::ASTFrontendAction::EndSourceFileAction();
}
private:
clang::FindClassAction *ConsumerFactory;
SourceFileCallbacks *Callbacks;
};
clang::FindClassAction *ConsumerFactory;
SourceFileCallbacks *Callbacks;
};
return std::unique_ptr<FrontendActionFactory>(
new FrontendActionFactoryAdapter(ConsumerFactory, Callbacks));
}
int main(int argc, char **argv)
{
vector<string> commands;
commands.push_back(argv[0]);
commands.push_back(argv[1]);
// convert commmands to `const char **`
const char **argList = new const char*[commands.size()];
for (vector<string>::size_type i = 0; i < commands.size(); ++i) {
argList[i] = commands[i].c_str();
// llvm::outs() << "path: " << commands[i] << "\n";
}
argc = commands.size();
CommonOptionsParser OptionsParser(argc, argList, MyToolCategory);
ClangTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList());
FindClassAction myAction;
Tool.run(newFrontendActionFactory<FindClassAction>(&myAction).get());
}
//file test.cpp test.h
class A
{
public:
int a;
int fnd()
{
return a+1;
}
};
command1:./bin/min-test /Users/zcfh/myTest/test.cpp result:
CXXRecordDecl 0x7fda2d8637a8 </Users/zcfh/myTest/test.cpp:2:1, line:10:1> line:2:7 class A definition
|-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal
| |-DefaultConstructor exists trivial needs_implicit
| |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
|-CXXRecordDecl 0x7fda2d8638d0 <col:1, col:7> col:7 implicit class A
|-AccessSpecDecl 0x7fda2d863960 <line:4:1, col:7> col:1 public
|-FieldDecl 0x7fda2d8639a0 <line:5:5, col:9> col:9 referenced a 'int'
`-CXXMethodDecl 0x7fda2d863a78 <line:6:5, line:9:5> line:6:9 fnd 'int ()'
`-CompoundStmt 0x7fda2d863bd8 <line:7:5, line:9:5>
`-ReturnStmt 0x7fda2d863bc8 <line:8:9, col:18>
`-BinaryOperator 0x7fda2d863ba8 <col:16, col:18> 'int' '+'
|-ImplicitCastExpr 0x7fda2d863b90 <col:16> 'int' <LValueToRValue>
| `-MemberExpr 0x7fda2d863b40 <col:16> 'int' lvalue ->a 0x7fda2d8639a0
| `-CXXThisExpr 0x7fda2d863b30 <col:16> 'A *' implicit this
`-IntegerLiteral 0x7fda2d863b70 <col:18> 'int' 1
commmand2:./bin/min-test /Users/zcfh/myTest/test.h result:
Running without flags.
/Users/zcfh/myTest/test.h:2:1: error: unknown type name 'class'
class A
^
/Users/zcfh/myTest/test.h:2:8: error: expected ';' after top level declarator
class A
^
;
2 errors generated.
test.cpp and test.h have the same content
CMakeList.txt
add_clang_executable(min-test
main.cpp
)
target_link_libraries(min-test
clangTooling
clangBasic
clangASTMatchers
)
Now, I know that the reason why it cannot run to VisitRecordDecl() is that the .h file will be parsed as a C file instead of C++. But the question now is how do I modify my code so that it can parse the .h file as C++
like clang++ can use “-x c++” parameter to get .h AST; Achieve the same effect in code
I solved this problem Add the argument "-xc++" before Tool.run();
Tool.appendArgumentsAdjuster(getInsertArgumentAdjuster("-xc++", ArgumentInsertPosition::BEGIN));
Tool.run(newFrontendActionFactory<FindClassAction>().get());
Because my English is not good, I may not describe the problem clearly.
来源:https://stackoverflow.com/questions/63148816/how-a-h-file-can-parse-as-c-in-clangtool