slurping include files

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

slurping include files

suppamax
 0 down vote favorite
       

I'd like to scan clang's AST. I started using some sample code provided in one tutorial.

My current code is

///////////////////////////////////////////////////////////////////////////////////////////////

#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[2],
                                                                     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;
}

///////////////////////////////////////////////////////////////////////////////////////////////

I run the executable in this way

./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

where infile.cpp begins with #include

and I obtain the following error

/usr/include/c++/4.6/iostream:39:10: fatal error: 'bits/c++config.h' file not found
#include <bits/c++config.h>

And I don't understand why, since /usr/include/c++/4.6/i686-linux-gnu includes bits/c++config.h

Could you please help clarifying?
Reply | Threaded
Open this post in threaded view
|

Re: slurping include files

suppamax
Sorry, after posting I identified a stupid mistake. I have to reformulate the question:



I'd like to scan clang's AST. I started using some sample code provided in one tutorial.

My current code is

#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;
}

I run the executable in this way

./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

where infile.cpp begins with

#include <iostream>

and I obtain the following error

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>
         ^

Could you please help clarifying?
Reply | Threaded
Open this post in threaded view
|

Re: slurping include files

Manuel Klimek
In general, getting clang to parse code with the code you have is hard :) That's why we have a tooling library to make that a lot easier. You can either use that directly, or look at the implementation to get hints around what you're doing wrong. My guess is that you're not using C++ mode ('namespace' error) and don't go through the driver's include directory detection.

See:

The implementation is here:

Cheers,
/Manuel



On Sun, Mar 17, 2013 at 4:04 PM, suppamax <[hidden email]> wrote:
Sorry, after posting I identified a stupid mistake. I have to reformulate the
question:



I'd like to scan clang's AST. I started using some sample code provided in
one tutorial.

My current code is

#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;
}

I run the executable in this way

./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

where infile.cpp begins with

#include <iostream>

and I obtain the following error

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>
         ^

Could you please help clarifying?




--
View this message in context: http://clang-developers.42468.n3.nabble.com/slurping-include-files-tp4031016p4031017.html
Sent from the Clang Developers mailing list archive at Nabble.com.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: slurping include files

suppamax
Hi Manuel,

thank you for your hint, I will have a look at libtooling.
Just a quick question: my final target is being able to rewrite my source code in some hot spots (variable declarations).

So:
1) do LibTooling also ease the rewriting procedure?
2) The reason why I started struggling with included files is my original code didn't react on variable declarations like
complex<float> c1;
and I imagined it was because the program didn't know how to react without loading the complex library. Any suggestion on how to perform this task?


Regards
Max
Reply | Threaded
Open this post in threaded view
|

Re: slurping include files

Vane, Edwin
1) LibTooling sure does have rewrite support! Take a look at the extra clang tools repo (instructions at the top of http://clang.llvm.org/docs/ClangTools.html). There's a few simple tools (remove-cstr-calls and tool-template) and one not-so-simple tool (cpp11-migrate) which use rewriting.
2) If you're using libtooling you get clang's header searching functionality for free. If the code you're about to rewrite can compile, you should be able to run your tool on it. Now, you may still get header problems. I think there was a problem just recently fixed for finding c++ headers buried within arch-specific directories (i.e. newer versions of Ubuntu). My workaround was to add the directory manually as a command-line flag e.g.: -I/usr/include/x86_64-linux-gnu/c++/4.7/

-----Original Message-----
From: [hidden email] [mailto:[hidden email]] On Behalf Of suppamax
Sent: Monday, March 18, 2013 11:54 AM
To: [hidden email]
Subject: Re: [cfe-dev] slurping include files

Hi Manuel,

thank you for your hint, I will have a look at libtooling.
Just a quick question: my final target is being able to rewrite my source code in some hot spots (variable declarations).

So:
1) do LibTooling also ease the rewriting procedure?
2) The reason why I started struggling with included files is my original code didn't react on variable declarations like complex<float> c1; and I imagined it was because the program didn't know how to react without loading the complex library. Any suggestion on how to perform this task?


Regards
Max



--
View this message in context: http://clang-developers.42468.n3.nabble.com/slurping-include-files-tp4031016p4031023.html
Sent from the Clang Developers mailing list archive at Nabble.com.
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev