How a .h file can parse as c++ in ClangTool

北城以北 提交于 2020-08-10 19:15:08

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!