0

I want to get AST of main function in source file (assuming there is one) to build control flow graph out of it. I found code that generates and traverse AST here: https://shaharmike.com/cpp/libclang/. But the problem is it goes into all included files. I also find this topic: Clang AST visitor, avoid traversing include files. But it seems that in clang10 some changes were made and suggested solution don't work now. Or maybe there is some other way to get AST for build control flow graph? Only requirement - it must work C++ source code.

luckydemon
  • 21
  • 5
  • 2
    Going into included files is necessary due to macros, which are not part of the final AST. Unless you want preprocessor AST? What exactly are you trying to achieve? – freakish Nov 26 '19 at 14:57
  • I want to build control flow graph for C++ code. But, becuase of task itself in my studies, I can't use already implement in any ways CFG builder (clang already has one). So, I thought that right way is to get part of AST with info about what is written and on what line it written in sourse file. And because of the task itself in university, the ultimate goal in not to create CFG builder that can cover anything, but create a program which can create CFG for simple programs and get a grasp on how it can be done. – luckydemon Nov 26 '19 at 15:22

2 Answers2

2

Reading the documentation teaches me that clang_visitChildren only goes "into" whatever it is pointing to if you return CXChildVisit_Recurse. So your visit function should inspect the cursor kind and return CXChildVisit_Continue until it reaches a function definition where the name equals main. What it does with main is up to you, but I suggest returning CXChildVisit_Break.

Botje
  • 26,269
  • 3
  • 31
  • 41
0

So, thanks to Botje and this post(https://www.phototalks.idv.tw/academic/?p=1932) I find the solution. Not the best code in any means, but it works. I hope it'll help others.

#include <iostream>
#include <clang-c/Index.h>
#include <string.h>
using namespace std;

ostream& operator<<(ostream& stream, const CXString& str)
{
  stream << clang_getCString(str);
  clang_disposeString(str);
  return stream;
}

std::string getCursorKindName( CXCursorKind cursorKind )
{
  CXString kindName  = clang_getCursorKindSpelling( cursorKind );
  std::string result = clang_getCString( kindName );

  clang_disposeString( kindName );
  return result;
}

std::string getCursorSpelling( CXCursor cursor )
{
  CXString cursorSpelling = clang_getCursorSpelling( cursor );
  std::string result      = clang_getCString( cursorSpelling );

  clang_disposeString( cursorSpelling );
  return result;
}
CXChildVisitResult visitor1( CXCursor cursor, CXCursor /* parent */, CXClientData clientData )
{
  CXSourceLocation location = clang_getCursorLocation( cursor );
    unsigned int locationstring =0;
     clang_getSpellingLocation  (   location, NULL, &locationstring, NULL,NULL);
  if( clang_Location_isFromMainFile( location ) == 0 )
    return CXChildVisit_Continue;
  CXCursorKind kind = clang_getCursorKind(cursor);
    std::string str2 ("main");
  CXCursorKind cursorKind = clang_getCursorKind( cursor );
  unsigned int curLevel  = *( reinterpret_cast<unsigned int*>( clientData ) );
  unsigned int nextLevel = curLevel + 1;
    std::cout << std::string( curLevel, '-' ) << " " << getCursorKindName(
    cursorKind ) << " (" << getCursorSpelling( cursor ) << ") ";
    std::cout << locationstring ;
    std::cout << endl;

    clang_visitChildren( cursor,
                         visitor1,
                         &nextLevel );
    return CXChildVisit_Continue;

}

CXChildVisitResult visitor( CXCursor cursor, CXCursor /* parent */, CXClientData clientData )
{
  CXSourceLocation location = clang_getCursorLocation( cursor );
  if( clang_Location_isFromMainFile( location ) == 0 )
    return CXChildVisit_Continue;
  CXCursorKind kind = clang_getCursorKind(cursor);
    std::string str2 ("main");
  CXCursorKind cursorKind = clang_getCursorKind( cursor );

  unsigned int curLevel  = *( reinterpret_cast<unsigned int*>( clientData ) );
  unsigned int nextLevel = curLevel + 1;
  if (!((str2.compare(getCursorSpelling(cursor)))))
  {
    std::cout << std::string( curLevel, '-' ) << " " << getCursorKindName(
    cursorKind ) << " (" << getCursorSpelling( cursor ) << ")\n";

    clang_visitChildren( cursor,
                         visitor1,
                         &nextLevel );
    return CXChildVisit_Continue;
  }
  else
  {
  return CXChildVisit_Continue;
  }
}

int main()
{
  CXIndex index = clang_createIndex(0, 0);
  CXTranslationUnit unit = clang_parseTranslationUnit(
     index,
     <source_file_name>, nullptr, 0,
    nullptr, 0,
     CXTranslationUnit_None);
      CXCursor cursor = clang_getTranslationUnitCursor(unit);
      unsigned int treeLevel = 0;
      clang_visitChildren( cursor, visitor, &treeLevel );
  clang_disposeTranslationUnit(unit);
  clang_disposeIndex(index);
}
luckydemon
  • 21
  • 5