草庐IT

c++ - clang 在解析 AST 时获取包含文件

coder 2024-02-12 原文

我想扫描 clang 的 AST。 我开始使用一个教程中提供的一些示例代码。

我当前的代码是

#include <iostream>

#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Casting.h"

#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"

#include "clang/Basic/LangOptions.h"
#include "clang/Basic/FileSystemOptions.h"

#include "clang/Basic/SourceManager.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Basic/FileManager.h"

#include "clang/Frontend/Utils.h"

#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"

#include "clang/Lex/Preprocessor.h"
#include "clang/Frontend/FrontendOptions.h"

#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/Builtins.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Sema/Sema.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Ownership.h"
#include "clang/AST/DeclGroup.h"

#include "clang/Parse/Parser.h"

#include "clang/Parse/ParseAST.h"
#include "clang/Frontend/CompilerInstance.h"

#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"

using namespace clang;
using namespace std;

// By implementing RecursiveASTVisitor, we can specify which AST nodes
// we're interested in by overriding relevant methods.
class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
{
public:
//  MyASTVisitor() : {} 
//  MyASTVisitor(Rewriter &R)
//      : TheRewriter(R)
//  {}

    bool VisitStmt(clang::Stmt *s) {
//      llvm::errs() << "Visiting statement\n";     
//      if (clang::isa<clang::BinaryOperator>(s)) {
//          if (cast<BinaryOperator>(s)->isAssignmentOp() == true) {
//              // blablabla
//          }
//      }
        return true;
    }

    bool VisitBinaryOperator(BinaryOperator* bo) {
        if (bo->isAssignmentOp() == true) {
            llvm::errs() << "Visiting assignment ";
            Expr *LHS;
            LHS = bo->getLHS();
            DeclRefExpr* dre;
            if ((dre = dyn_cast<DeclRefExpr>(LHS))) { 
                string name = (dre->getNameInfo()).getName().getAsString();
                llvm::errs() << "to " << name;
            }
            if (ArraySubscriptExpr* ase = dyn_cast<ArraySubscriptExpr>(LHS)) { 
                Expr *arrayBase = ase->getBase()->IgnoreParenCasts();
                if ((dre = dyn_cast<DeclRefExpr>(arrayBase))) { 
                    string name = (dre->getNameInfo()).getName().getAsString();
                    llvm::errs() << "to array " << name;
                }
            }
            llvm::errs() << "\n";
        }
        return true;
    }

    bool shouldVisitTemplateInstantiations() const { 
        llvm::errs() << "PIPPOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" << "\n";
        return true; }

    bool VisitCXXOperatorCallExprs(CXXOperatorCallExpr *e) {
        llvm::errs() << "Visiting cxxoperatorcall" << "\n";
        return true;
    }

    bool VisitCXXConstructorDecl(CXXConstructorDecl *c) {
        llvm::errs() << "Visiting CXXConstructorDecl" << "\n";
        return true;        
    }

    bool VisitDeclRefExpr(DeclRefExpr* expr) {
        string name = (expr->getNameInfo()).getName().getAsString();
        llvm::errs() << name << "\n";
        return true;
    }

    bool VisitVarDecl(VarDecl *v) {
        llvm::errs() << "Visiting declaration of variable " << v->getDeclName().getAsString() << "\n";
        llvm::errs() << "  type: " << v->getTypeSourceInfo()->getType().getTypePtr()->getTypeClassName();
        if (v->getTypeSourceInfo()->getType().getTypePtr()->isFloatingType() == true) {
            llvm::errs() << " -> float";
        }
        if(v->getTypeSourceInfo()->getType().getTypePtr()->isConstantArrayType() == true) {
            llvm::errs() << " of ";
            llvm::errs() << v->getTypeSourceInfo()->getType().getAsString();
            llvm::errs() << " size ";
            llvm::APInt arraySize = cast<ConstantArrayType>(v->getTypeSourceInfo()->getType().getTypePtr())->getSize();
            llvm::errs() << arraySize;
        }
        if(v->getTypeSourceInfo()->getType().getTypePtr()->isPointerType() == true) {
            llvm::errs() << " to " << v->getTypeSourceInfo()->getType().getAsString();

        }
        llvm::errs() << "\n";
        return true;
    }

  bool VisitTypedefDecl(clang::TypedefDecl *d) {
        llvm::errs() << "Visiting " << d->getDeclKindName() << " " << d->getName() << "\n";

        return true; // returning false aborts the traversal        
    }

    bool VisitFunctionDecl(FunctionDecl *f) {
        llvm::errs() << "Visiting function " << f->getNameInfo().getName().getAsString() << "\n";

        return true;
    }



private:
//  Rewriter &TheRewriter;
};


// Implementation of the ASTConsumer interface for reading an AST produced
// by the Clang parser.
class MyASTConsumer : public ASTConsumer
{
public:
    MyASTConsumer() : Visitor() {}
//  MyASTConsumer(Rewriter &R)
//      : Visitor(R)
//  {}

    // Override the method that gets called for each parsed top-level
    // declaration.
    virtual bool HandleTopLevelDecl(DeclGroupRef DR) {
        for (DeclGroupRef::iterator b = DR.begin(), e = DR.end();
                 b != e; ++b)
            // Traverse the declaration using our AST visitor.
            Visitor.TraverseDecl(*b);
        return true;
    }

private:
    MyASTVisitor Visitor;
};


int main(int argc, char** argv)
{
    if (argc < 2) {
        llvm::errs() << "Usage: rewritersample <filename> libs\n";
        return 1;
    }

    clang::DiagnosticOptions diagnosticOptions;
    clang::TextDiagnosticPrinter *pTextDiagnosticPrinter =
        new clang::TextDiagnosticPrinter(
            llvm::outs(),
            &diagnosticOptions);
    llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> pDiagIDs;
    clang::DiagnosticsEngine *pDiagnosticsEngine =
        new clang::DiagnosticsEngine(pDiagIDs,
            &diagnosticOptions,
            pTextDiagnosticPrinter);

    clang::LangOptions languageOptions;
    clang::FileSystemOptions fileSystemOptions;
    clang::FileManager fileManager(fileSystemOptions);

    clang::SourceManager sourceManager(
        *pDiagnosticsEngine,
        fileManager);

    llvm::IntrusiveRefCntPtr<clang::HeaderSearchOptions> headerSearchOptions(new clang::HeaderSearchOptions());
        headerSearchOptions->ResourceDir = "/opt/llvm_build" "/lib/clang/" CLANG_VERSION_STRING;
    // <Warning!!> -- Platform Specific Code lives here
    // This depends on A) that you're running linux and
    // B) that you have the same GCC LIBs installed that
    // I do.
    // Search through Clang itself for something like this,
    // go on, you won't find it. The reason why is Clang
    // has its own versions of std* which are installed under
    // /usr/local/lib/clang/<version>/include/
    // See somewhere around Driver.cpp:77 to see Clang adding
    // its version of the headers to its include path.
        for (int i = 2; i < argc; i++) {
            headerSearchOptions->AddPath(argv[i],
                                                                     clang::frontend::Angled,
                                                                     false,
                                                                     false);
        }
    // </Warning!!> -- End of Platform Specific Code

    clang::TargetOptions targetOptions;
    targetOptions.Triple = llvm::sys::getDefaultTargetTriple();

    clang::TargetInfo *pTargetInfo =
        clang::TargetInfo::CreateTargetInfo(
            *pDiagnosticsEngine,
            &targetOptions);

    clang::HeaderSearch headerSearch(headerSearchOptions,
                                     fileManager,
                                     *pDiagnosticsEngine,
                                     languageOptions,
                                     pTargetInfo);
    clang::CompilerInstance compInst;

    llvm::IntrusiveRefCntPtr<clang::PreprocessorOptions> pOpts( new clang::PreprocessorOptions());
    clang::Preprocessor preprocessor(
        pOpts,
        *pDiagnosticsEngine,
        languageOptions,
        pTargetInfo,
        sourceManager,
        headerSearch,
        compInst);

    clang::FrontendOptions frontendOptions;
    clang::InitializePreprocessor(
        preprocessor,
        *pOpts,
        *headerSearchOptions,
        frontendOptions);

    const clang::FileEntry *pFile = fileManager.getFile(
        argv[1]);
    sourceManager.createMainFileID(pFile);

    const clang::TargetInfo &targetInfo = *pTargetInfo;

    clang::IdentifierTable identifierTable(languageOptions);
    clang::SelectorTable selectorTable;

    clang::Builtin::Context builtinContext;
    builtinContext.InitializeTarget(targetInfo);
    clang::ASTContext astContext(
        languageOptions,
        sourceManager,
        pTargetInfo,
        identifierTable,
        selectorTable,
        builtinContext,
        0 /* size_reserve*/);
   MyASTConsumer astConsumer;

    clang::Sema sema(
        preprocessor,
        astContext,
        astConsumer);

    pTextDiagnosticPrinter->BeginSourceFile(languageOptions, &preprocessor);
    clang::ParseAST(preprocessor, &astConsumer, astContext);
    pTextDiagnosticPrinter->EndSourceFile();
    return 0;
}

我以这种方式运行可执行文件

./ast_analyzer infile.cpp /usr/include/c++/4.6 /usr/include/c++/4.6/i686-linux-gnu /usr/include/c++/4.6/parallel/ /usr/include/c++/4.6/tr1 /usr/include/i386-linux-gnu/c++/4.6 /usr/include/c++/4.6 /usr/include /usr/src/linux-headers-3.2.0-35/include/linux /usr/src/linux-headers-3.2.0-35/include

infile.cpp 开始于

#include <iostream>

我得到以下错误

In file included from input04.c:1:
In file included from /usr/include/c++/4.6/iostream:40:
In file included from /usr/include/c++/4.6/ostream:40:
In file included from /usr/include/c++/4.6/ios:39:
In file included from /usr/include/c++/4.6/iosfwd:41:
/usr/include/c++/4.6/bits/stringfwd.h:43:1: error: unknown type name 'namespace'
namespace std _GLIBCXX_VISIBILITY(default)
^
/usr/include/c++/4.6/bits/stringfwd.h:43:43: error: expected ';' after top level    declarator
namespace std _GLIBCXX_VISIBILITY(default)
                                      ^
In file included from input04.c:1:
In file included from /usr/include/c++/4.6/iostream:40:
In file included from /usr/include/c++/4.6/ostream:40:
In file included from /usr/include/c++/4.6/ios:42:
In file included from /usr/include/c++/4.6/bits/localefwd.h:42:
In file included from /usr/include/c++/4.6/i686-linux-gnu/bits/c++locale.h:42:
In file included from /usr/include/c++/4.6/clocale:44:
/usr/include/locale.h:30:10: fatal error: 'bits/locale.h' file not found
#include <bits/locale.h>
         ^

你能帮忙解释一下吗?

最佳答案

当您调用 headerSearchOptions->AddPath 时,您硬编码了值 2,但它应该是 i

关于c++ - clang 在解析 AST 时获取包含文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15466939/

有关c++ - clang 在解析 AST 时获取包含文件的更多相关文章

  1. Ruby 解析字符串 - 2

    我有一个字符串input="maybe(thisis|thatwas)some((nice|ugly)(day|night)|(strange(weather|time)))"Ruby中解析该字符串的最佳方法是什么?我的意思是脚本应该能够像这样构建句子:maybethisissomeuglynightmaybethatwassomenicenightmaybethiswassomestrangetime等等,你明白了......我应该一个字符一个字符地读取字符串并构建一个带有堆栈的状态机来存储括号值以供以后计算,还是有更好的方法?也许为此目的准备了一个开箱即用的库?

  2. ruby - 使用 RubyZip 生成 ZIP 文件时设置压缩级别 - 2

    我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看ruby​​zip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d

  3. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  4. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  5. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  6. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  7. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  8. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  9. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  10. ruby - 用逗号、双引号和编码解析 csv - 2

    我正在使用ruby​​1.9解析以下带有MacRoman字符的csv文件#encoding:ISO-8859-1#csv_parse.csvName,main-dialogue"Marceu","Giveittohimóhe,hiswife."我做了以下解析。require'csv'input_string=File.read("../csv_parse.rb").force_encoding("ISO-8859-1").encode("UTF-8")#=>"Name,main-dialogue\r\n\"Marceu\",\"Giveittohim\x97he,hiswife.\"\

随机推荐