Title: How to get AST only of main function using clang
Tags: c++;clang;abstract-syntax-tree;control-flow-graph
Question: 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.

Comment: 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.

Comment: 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?


Here is another answer: 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```.


Here is another answer: 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&gt;
#include <clang-c/Index.h&gt;
#include <string.h&gt;
using namespace std;

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

st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16string getCursorKindName( CXCursorKind cursorKind )
{
  CXString kindName  = clang_getCursorKindSpelling( cursorKind );
  st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16string result = clang_getCString( kindName );

  clang_disposeString( kindName );
  return result;
}

st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16string getCursorSpelling( CXCursor cursor )
{
  CXString cursorSpelling = clang_getCursorSpelling( cursor );
  st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16string 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, &amp;locationstring, NULL,NULL);
  if( clang_Location_isFromMainFile( location ) == 0 )
    return CXChildVisit_Continue;
  CXCursorKind kind = clang_getCursorKind(cursor);
    st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16string str2 ("main");
  CXCursorKind cursorKind = clang_getCursorKind( cursor );
  unsigned int curLevel  = *( reinterpret_cast<unsigned int*&gt;( clientData ) );
  unsigned int nextLevel = curLevel + 1;
    st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16cout << st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16string( curLevel, '-' ) << " " << getCursorKindName(
    cursorKind ) << " (" << getCursorSpelling( cursor ) << ") ";
    st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16cout << locationstring ;
    st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16cout << endl;

    clang_visitChildren( cursor,
                         visitor1,
                         &amp;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);
    st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16string str2 ("main");
  CXCursorKind cursorKind = clang_getCursorKind( cursor );

  unsigned int curLevel  = *( reinterpret_cast<unsigned int*&gt;( clientData ) );
  unsigned int nextLevel = curLevel + 1;
  if (!((str2.compare(getCursorSpelling(cursor)))))
  {
    st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16cout << st181a:6c1c:918f:f3a4:2e8c:61d6:1a08:6b16string( curLevel, '-' ) << " " << getCursorKindName(
    cursorKind ) << " (" << getCursorSpelling( cursor ) << ")\n";

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

int main()
{
  CXIndex index = clang_createIndex(0, 0);
  CXTranslationUnit unit = clang_parseTranslationUnit(
     index,
     <source_file_name&gt;, nullptr, 0,
    nullptr, 0,
     CXTranslationUnit_None);
      CXCursor cursor = clang_getTranslationUnitCursor(unit);
      unsigned int treeLevel = 0;
      clang_visitChildren( cursor, visitor, &amp;treeLevel );
  clang_disposeTranslationUnit(unit);
  clang_disposeIndex(index);
}
```


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 2, 'CommentCount': 2, 'ContentLicense': 'CC BY-SA 4.0', 'CreationDate': '2019:00:11/26/19', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<c++><clang><abstract-syntax-tree><control-flow-graph>', 'Title': 'How to get AST only of main function using clang', 'ViewCount': 660, 'id': 59053559, 'user_AboutMe': None, 'user_AccountId': 14564370.0, 'user_DisplayName': 'luckydemon', 'user_Reputation': 21.0, 'user_Views': 21.0, 'user_id': 10519594.0}}