Domanda

I'm writing a little tool with llvm to parse C and C++ code, but I can't seem to get it to successfully parse C++ at all. I'm probably missing something obvious.

This is what I have so far:

#include <iostream>

#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"

#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/LangStandard.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/DirectoryLookup.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Parse/ParseAST.h"

class MyASTConsumer : public clang::ASTConsumer {
    public:
        bool HandleTopLevelDecl(clang::DeclGroupRef d);
        virtual ~MyASTConsumer() { }
};

bool MyASTConsumer::HandleTopLevelDecl(clang::DeclGroupRef d)
{
    for(auto ii = d.begin(); ii != d.end(); ii++)
    {
        printf("decl type: %s\n", (*ii)->getDeclKindName()); 
        auto namedDecl = llvm::dyn_cast<clang::NamedDecl>(*ii);
        if(namedDecl)
        {
            printf("name: %s\n", namedDecl->getName().data());
        }
    }

    return true;
}

int main(int, char **argv)
{
    using clang::CompilerInstance;
    using clang::TargetOptions;
    using clang::TargetInfo;
    using clang::FileEntry;
    using clang::DiagnosticOptions;
    using clang::TextDiagnosticPrinter;
    using clang::SrcMgr::CharacteristicKind;
    using clang::StringRef;
    using clang::DirectoryLookup;
    using llvm::MemoryBuffer;
    using clang::LangOptions;
    using clang::FrontendOptions;
    using clang::LangStandard;
    using clang::CompilerInvocation;
    using clang::InitializePreprocessor;
    using clang::Preprocessor;
    using clang::PreprocessorOptions;
    using clang::HeaderSearch;
    using clang::HeaderSearchOptions;

    CompilerInstance ci;
    DiagnosticOptions diagnosticOptions;
    ci.createDiagnostics();

    CompilerInvocation *invocation = new CompilerInvocation;

    LangOptions &langOpts = ci.getLangOpts();
    langOpts.RTTI = 1;
    langOpts.Bool = 1;
    langOpts.CPlusPlus11 = 1;
    langOpts.GNUKeywords = 1;
    langOpts.CXXExceptions = 1;
    langOpts.POSIXThreads = 1;
    langOpts.SpellChecking = 1;

    invocation->setLangDefaults(langOpts, clang::IK_CXX, LangStandard::lang_gnucxx11);

    ci.setInvocation(invocation);

    llvm::IntrusiveRefCntPtr<TargetOptions> pto( new TargetOptions() );
    pto->Triple = llvm::sys::getDefaultTargetTriple();

    llvm::IntrusiveRefCntPtr<TargetInfo> pti(TargetInfo::CreateTargetInfo(ci.getDiagnostics(), pto.getPtr()));
    ci.setTarget(pti.getPtr());

    ci.createFileManager();
    auto &fileManager = ci.getFileManager();

    ci.createSourceManager(fileManager);

    llvm::IntrusiveRefCntPtr<HeaderSearchOptions> headerSearchOpts( new HeaderSearchOptions() );

    ci.createPreprocessor();
    auto &pp = ci.getPreprocessor();
    pp.setPredefines(builtinMacros);

    HeaderSearch &headerSearch = pp.getHeaderSearchInfo();

    for(auto &inc: builtinIncludePaths)
    {
        auto dirEntry = fileManager.getDirectory(StringRef(inc), true);
        DirectoryLookup dirLookup(dirEntry, CharacteristicKind::C_System, false);
        headerSearch.AddSearchPath (dirLookup, true);
    }

    MyASTConsumer *astConsumer = new MyASTConsumer();
    ci.setASTConsumer(astConsumer);

    ci.createASTContext();

    const FileEntry *pFile = fileManager.getFile(argv[1]);
    auto &sourceManager = ci.getSourceManager();

    sourceManager.createMainFileID(pFile);
    ci.getDiagnosticClient().BeginSourceFile(
        ci.getLangOpts(),
        &pp
    );

    clang::ParseAST(pp, astConsumer, ci.getASTContext());
    ci.getDiagnosticClient().EndSourceFile();

    return 0;
}

It does parse C just fine, but it errors out on the namespace keyword and extern "C" { blocks. So far I'm stumped. If anyone has a clue, something I'm missing, please share.

È stato utile?

Soluzione

I believe I figured out the problem. You should always call setInvocation on the compiler instance before calling a lot of the methods on the compiler instance, as it actually just proxies to the invocation.

I moved the setInvocation call to right after the CompilerInvocation object is created, and things now work.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top