[cfe-dev] slurping include files
Manuel Klimek
klimek at google.com
Mon Mar 18 07:59:07 PDT 2013
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:
http://clang.llvm.org/docs/LibTooling.html
The implementation is here:
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Tooling.cpp?view=markup
Cheers,
/Manuel
On Sun, Mar 17, 2013 at 4:04 PM, suppamax <max.giacometti at gmail.com> 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
> cfe-dev at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20130318/5404aebc/attachment.html>
More information about the cfe-dev
mailing list