[cfe-dev] FW: Parsing C++ Header file

Raghavendra K raghavendrak at huawei.com
Thu May 30 00:03:54 PDT 2013


________________________________________
From: Raghavendra K
Sent: Thursday, May 30, 2013 12:13 PM
To: cfe-dev at cs.uiuc.edu; annulen at yandex.ru
Cc: Arvind Saraswat; Linxiaowen
Subject: Parsing C++ Header file

Hi,

Related to parsing header files, code is as below,

logic is in this function ==> Decl* VisitRecordDecl(RecordDecl *D),

In this  function, pCXXRecord->getDescribedClassTemplate(); //is always NULL

Pls hlep how to proceed further


regards
ragha



#include <cstdio>
#include <string>
#include <sstream>

#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/CommandLine.h"

using namespace clang;
using namespace std;


  FILE* flogs;

clang::LangOptions* planguageOptions = NULL;

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


    Decl* VisitRecordDecl(RecordDecl *D)
    {
       if(D->isClass() == true)
       {

         if(strstr(D->getQualifiedNameAsString().c_str(),"std::")
            ||
            strstr(D->getQualifiedNameAsString().c_str(),"__gnu_cxx::"))
         {
           return D;
         }


          fprintf(flogs,"ClassName=%s\n",D->getQualifiedNameAsString().c_str());

          RecordDecl::field_iterator classfieldItr = D->field_begin();
          RecordDecl::field_iterator classfieldItrEnd =  D->field_end();
          for(;classfieldItr != classfieldItrEnd; classfieldItr++)
          {

              //Array Handling Todo
              if((*classfieldItr)->getType().getTypePtrOrNull()->isArrayType() == true)
              {
                //TODO:how to get the base type and chk if it is simple or complex type
                fprintf(flogs,"FieldName=%s is Array Type\n",classfieldItr->getQualifiedNameAsString().c_str());
              }
              //Array Handling Todo

              if((*classfieldItr)->getType().getTypePtrOrNull()->isStructureOrClassType() == false)
              {
                fprintf(flogs,"FieldName=%s is not Complex Type,Its Name=%s,\n",classfieldItr->getQualifiedNameAsString().c_str(),(*classfieldItr)->getType().getTypePtrOrNull()->getTypeClassName());

                //generate code by calling encode_(i);

                if((*classfieldItr)->getType().getTypePtrOrNull()->isPointerType() == true)
                {
                   continue;
                }

                fprintf(flogs,"****encodeBasic(%s)\n",classfieldItr->getQualifiedNameAsString().c_str());

              }
              else
              {
               fprintf(flogs,"FieldName=%s is Complex Type,Its Name=%s,\n",classfieldItr->getQualifiedNameAsString().c_str(),(*classfieldItr)->getType().getTypePtrOrNull()->getTypeClassName());



                  fprintf(flogs,"Desugar=%s",(*classfieldItr)->getType().getTypePtrOrNull()->getUnqualifiedDesugaredType()->getTypeClassName());
                  CXXRecordDecl* fieldClass = (*classfieldItr)->getType().getTypePtrOrNull()->getUnqualifiedDesugaredType()->getAsCXXRecordDecl();
                  if(fieldClass != NULL)
                  {
                    if(fieldClass->getQualifiedNameAsString()== "std::string"
                       ||
                     fieldClass->getQualifiedNameAsString()== "std::basic_string")
                    {
                      fprintf(flogs,"****encodeString\n");
                        continue;
                    }
                    if( fieldClass->getQualifiedNameAsString()== "std::map")
                    {
                      fprintf(flogs,"****encodeMAP\n");
                      RecordDecl* oriClass =  ((*classfieldItr)->getParent());
                      if(oriClass)
                      {
                         CXXRecordDecl* pCXXRecord = (CXXRecordDecl*)oriClass->getDefinition();
                         if(pCXXRecord)
                         {
                         fprintf(flogs,"****1\n");
                         ClassTemplateDecl* classTemp = pCXXRecord->getDescribedClassTemplate(); //is always NULL
                         if(classTemp)
                         {
                         fprintf(flogs,"****2\n");
                           TemplateParameterList* tempList = classTemp->getTemplateParameters();
                           if(tempList)
                           fprintf(flogs,"****SOFAR SO GOOD\n");
                         }
                         }
                      }

                      continue;
                    }

                    if(fieldClass->getQualifiedNameAsString()== "std::list")
                    {
                      fprintf(flogs,"****encodeList\n");
                        continue;
                    }

                    //anything else i.e full object
                    fprintf(flogs,"**** %s.encode\n",fieldClass->getQualifiedNameAsString().c_str());
                  }
              }
          }
       }
       return D;
    }


private:


    Rewriter &TheRewriter;
};


// Implementation of the ASTConsumer interface for reading an AST produced
// by the Clang parser.
class MyASTConsumer : public ASTConsumer
{
public:
    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;
};
static llvm::cl::list<string> directorySearchPathList("I", llvm::cl::value_desc("Directory_"),llvm::cl::Prefix,llvm::cl::desc("<Specify Include Directory Search Path>"));

static llvm::cl::opt<string> InputFilename(llvm::cl::Positional,llvm::cl::value_desc("FileName_"),llvm::cl::Required,llvm::cl::desc("<input file>"));

int main(int argc, char *argv[])
{

   flogs = fopen("logs","w");

   llvm::cl::ParseCommandLineOptions(argc, argv);

    printf("****INPUTFileName=%s\n",InputFilename.c_str());


    // CompilerInstance will hold the instance of the Clang compiler for us,
    // managing the various objects needed to run the compiler.

    CompilerInstance TheCompInst;
    clang::LangOptions& languageOptions = TheCompInst.getLangOpts();
    planguageOptions = &languageOptions;
    CompilerInvocation::setLangDefaults(languageOptions,IK_CXX);

    HeaderSearchOptions& headOptions = TheCompInst.getHeaderSearchOpts();


    for (int i = 0; i < directorySearchPathList.size(); ++i)
    {
    //  fprintf(flogs,"****HEAD=%s",directorySearchPathList[i].c_str());
      headOptions.AddPath(directorySearchPathList[i],clang::frontend::Angled,true,false,false);
    }

    //headOptions.AddSystemHeaderPrefix("/usr/include/c++/4.1.2",true);
    headOptions.Verbose = 1;

    TheCompInst.createDiagnostics(0, 0);


    // Initialize target info with the default triple for our platform.
    TargetOptions* TO = new TargetOptions;
    TO->Triple = llvm::sys::getDefaultTargetTriple();
    TargetInfo *TI = TargetInfo::CreateTargetInfo( TheCompInst.getDiagnostics(), *TO);
    TheCompInst.setTarget(TI);

    TheCompInst.createFileManager();
    FileManager &FileMgr = TheCompInst.getFileManager();
    TheCompInst.createSourceManager(FileMgr);
    SourceManager &SourceMgr = TheCompInst.getSourceManager();
    TheCompInst.createPreprocessor();
    TheCompInst.createASTContext();


    // A Rewriter helps us manage the code rewriting task.
    Rewriter TheRewriter;
    TheRewriter.setSourceMgr(SourceMgr, TheCompInst.getLangOpts());

    // Set the main file handled by the source manager to the input file.
    const FileEntry *FileIn = FileMgr.getFile(InputFilename.c_str());
    SourceMgr.createMainFileID(FileIn);
    TheCompInst.getDiagnosticClient().BeginSourceFile( TheCompInst.getLangOpts(), &TheCompInst.getPreprocessor());

    // Create an AST consumer instance which is going to get called by
    // ParseAST.
    MyASTConsumer TheConsumer(TheRewriter);

    // Parse the file to AST, registering our consumer as the AST consumer.
    ParseAST(TheCompInst.getPreprocessor(), &TheConsumer, TheCompInst.getASTContext());

    printf("everything ok");

    // At this point the rewriter's buffer should be full with the rewritten
    // file contents.
    const RewriteBuffer *RewriteBuf =
        TheRewriter.getRewriteBufferFor(SourceMgr.getMainFileID());
    llvm::outs() << string(RewriteBuf->begin(), RewriteBuf->end());

    //TheCompInst->setTarget(NULL);

    return 0;
}




More information about the cfe-dev mailing list