<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<style type="text/css" style="display:none;"><!-- P {margin-top:0;margin-bottom:0;} --></style>
</head>
<body dir="ltr">
<div id="divtagdefaultwrapper" style="font-size:12pt;color:#000000;background-color:#FFFFFF;font-family:Calibri,Arial,Helvetica,sans-serif;">
<p>Hello ,</p>
<p><br>
</p>
<p>As the title states, I have an AST visitor which extracts some information from source files. </p>
<p>I will pass a source file in main as input file and I expect it to include the nescecarry header files to correctly identify the variable types and everything. </p>
<p>The problem is that I dont want it to print me any information for source code which is outside my main file even if it uses source code from header files. </p>
<p>I tried to implement it but it doesn't work. Can you help me? Here is my complete code:</p>
<p><br>
</p>
<p></p>
<div>#include "clang/Driver/Options.h"</div>
<div>#include "clang/AST/AST.h"</div>
<div>#include "clang/AST/ASTContext.h"</div>
<div>#include "clang/AST/ASTConsumer.h"</div>
<div>#include "clang/AST/RecursiveASTVisitor.h"</div>
<div>#include "clang/Frontend/ASTConsumers.h"</div>
<div>#include "clang/Frontend/FrontendActions.h"</div>
<div>#include "clang/Frontend/CompilerInstance.h"</div>
<div>#include "clang/Tooling/CommonOptionsParser.h"</div>
<div>#include "clang/Tooling/Tooling.h"</div>
<div>#include "clang/Rewrite/Core/Rewriter.h"</div>
<div>#include "clang/Basic/SourceManager.h"</div>
<div>#include <iostream></div>
<div>#include <fstream></div>
<div><br>
</div>
<div>using namespace std;</div>
<div>using namespace clang;</div>
<div>using namespace clang::driver;</div>
<div>using namespace clang::tooling;</div>
<div>using namespace llvm;</div>
<div><br>
</div>
<div>int numFunctions = 0;</div>
<div>int numVariables = 0;</div>
<div>int numFuncCalls = 0;</div>
<div>int append;</div>
<div><br>
</div>
<div>ofstream APIs, REPORT;</div>
<div>LangOptions LangOpts;</div>
<div>PrintingPolicy Policy(LangOpts);</div>
<div><br>
</div>
<div>//function which checks if the specified file exists or not.</div>
<div>bool fexists(const char *filename)</div>
<div>{</div>
<div> ifstream ifile(filename);</div>
<div> return ifile;</div>
<div>}</div>
<div><br>
</div>
<div>class ExampleVisitor : public RecursiveASTVisitor<ExampleVisitor> {</div>
<div>private:</div>
<div> ASTContext *astContext; // used for getting additional AST info</div>
<div>public:</div>
<div> explicit ExampleVisitor(CompilerInstance *CI)</div>
<div> : astContext(&(CI->getASTContext()))// directly initialize private members</div>
<div> {</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>}</div>
<div><br>
</div>
<div> bool VisitVarDecl(VarDecl *var)</div>
<div> {</div>
<div> FullSourceLoc FullLocation = astContext->getFullLoc(var->getLocStart());</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>FileID fileID = FullLocation.getFileID();</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>SourceManager &SM = astContext->getSourceManager();</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>FileID MFileID = SM.getMainFileID();</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>//unsigned int mainFileID = MFileID.getHashValue();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>//unsigned int thisFileID = fileID.getHashValue();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>//cout << mainFileID << " " << thisFileID << endl;</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>if (SM.isInMainFile(var->getLocStart())) //checks if the node is in the main = input file.</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>{</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>if(var->hasLocalStorage() || var->isStaticLocal ())</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>{</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>//var->dump(); //prints the corresponding line of the AST.</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>numVariables++;</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>string varName = var->getQualifiedNameAsString();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>string varType = var->getType().getAsString();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>REPORT << "Variable Declaration: " << varName << " of type " << varType << "\n";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>APIs << varType << ",";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>}</div>
<div> return true;</div>
<div> }</div>
<div><br>
</div>
<div> bool VisitFunctionDecl(FunctionDecl *func)</div>
<div> {</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> FullSourceLoc FullLocation = astContext->getFullLoc(func->getLocStart());</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> FileID fileID = FullLocation.getFileID();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> //unsigned int thisFileID = fileID.getHashValue();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> //cout << thisFileID << endl;</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> SourceManager &SM = astContext->getSourceManager();</div>
<div> //FileID MFileID = SM.getMainFileID();</div>
<div> //unsigned int mainFileID = MFileID.getHashValue();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> //cout << mainFileID << " " << thisFileID << endl;</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> </div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> if(SM.isInMainFile(func->getLocStart())) //checks if the node is in the main (input) file.</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> {</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> string funcName = func->getNameInfo().getName().getAsString();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> string funcType = func->getResultType().getAsString();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> //func ->dump(); //prints the corresponding line of the AST.</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> REPORT << "Function Declaration: " << funcName << " of type " << funcType << "\n";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> if (append == 0 && numFunctions == 0)</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span> APIs << funcName <<":";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> else</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span><span class="Apple-tab-span" style="white-space:pre"></span> APIs << "\n" << funcName <<":";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> APIs <<funcType << ",";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> numFunctions++;</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> }</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span> return true;</div>
<div> }</div>
<div><br>
</div>
<div> bool VisitStmt(Stmt *st)</div>
<div> {</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>FullSourceLoc FullLocation = astContext->getFullLoc(st->getLocStart());</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>FileID fileID = FullLocation.getFileID();</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>//unsigned int thisFileID = fileID.getHashValue();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>SourceManager &SM = astContext->getSourceManager();</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>if(SM.isInMainFile(st->getLocStart())) //checks if the node is in the main = input file.</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>{</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>if (CallExpr *call = dyn_cast<CallExpr>(st))</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>{</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>numFuncCalls++;</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>call->dump(); //prints the corresponding line of the AST.</div>
<div> <span class="Apple-tab-span" style="white-space:pre"> </span>FunctionDecl *func_decl;</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>if(call->getDirectCallee())</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>{</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>func_decl = call ->getDirectCallee();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>string funcCall = func_decl->getNameInfo().getName().getAsString();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>REPORT << "Function call: " << funcCall << " with arguments ";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>APIs << funcCall << ",";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>for(int i=0, j = call->getNumArgs(); i<j; i++)</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>{</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>//For each argument it prints its type. The function must be declared otherwise it will return int-for unknown argument type.</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>APIs << call->getArg(i)->getType().getAsString()<< ",";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>REPORT << call->getArg(i)->getType().getAsString() << ", ";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>REPORT << "\n";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>/*else</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>{</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>Expr *expr = call->getCallee();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>string exprCall = expr ->getStmtClassName();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>REPORT << "Expression call: " << exprCall << " with arguments ";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>APIs << exprCall << ",";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>for(int i=0, j = call->getNumArgs(); i<j; i++)</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>{</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>//For each argument it prints its type. The function must be declared otherwise it will return int-for unknown argument type.</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>APIs << call->getArg(i)->getType().getAsString()<< ",";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>REPORT << call->getArg(i)->getType().getAsString() << ", ";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>REPORT << "\n";</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>*/</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>}</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>}</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>return true;</div>
<div> }</div>
<div>};</div>
<div><br>
</div>
<div>//Creating an ASTConsumer</div>
<div>class ExampleASTConsumer : public ASTConsumer</div>
<div>{</div>
<div>private:</div>
<div> ExampleVisitor *Visitor; // doesn't have to be private</div>
<div><br>
</div>
<div>public:</div>
<div> // override the constructor in order to pass CI</div>
<div> explicit ExampleASTConsumer(CompilerInstance *CI)</div>
<div> : Visitor(new ExampleVisitor(CI))</div>
<div> { }</div>
<div><br>
</div>
<div> // override this to call our ExampleVisitor on the entire source file</div>
<div> virtual void HandleTranslationUnit(ASTContext &Context) {</div>
<div> /* we can use ASTContext to get the TranslationUnitDecl, which is</div>
<div> a single Decl that collectively represents the entire source file */</div>
<div> Visitor->TraverseDecl(Context.getTranslationUnitDecl());</div>
<div> }</div>
<div>};</div>
<div><br>
</div>
<div><br>
</div>
<div>//Creating a FrontendAction</div>
<div>//This is very similar with the official tutorial of clang about RecursiveASTVisitor</div>
<div>class ExampleFrontendAction : public ASTFrontendAction</div>
<div>{</div>
<div>public://this is from the basic tutorial.</div>
<div> virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, StringRef file)</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>{</div>
<div> return new ExampleASTConsumer(&CI); // pass CI pointer to ASTConsumer</div>
<div> }</div>
<div>};</div>
<div><br>
</div>
<div><br>
</div>
<div><br>
</div>
<div>int main(int argc, const char **argv)</div>
<div>{</div>
<div> if (argc < 3)</div>
<div> {</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>cerr << "usage: " << argv[0] << " <filename> --" << endl;</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>return EXIT_FAILURE;</div>
<div> }</div>
<div><br>
</div>
<div><br>
</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>if (!fexists(argv[1]))</div>
<div> {</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>cerr << "Specified input file does not exist." << endl;</div>
<div> <span class="Apple-tab-span" style="white-space:pre"></span>return EXIT_FAILURE;</div>
<div> }</div>
<div><br>
</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>if (fexists("API.txt"))</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>append = 1; //it means will append the file.</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>else</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>append = 0;</div>
<div> APIs.open ("API.txt", ios::out | ios::app);</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>REPORT.open("report.txt");</div>
<div><br>
</div>
<div> // parse the command-line args passed to your code</div>
<div> CommonOptionsParser op(argc, argv);</div>
<div><br>
</div>
<div> // create a new Clang Tool instance (a LibTooling environment)</div>
<div> ClangTool Tool(op.getCompilations(), op.getSourcePathList());</div>
<div><br>
</div>
<div> // run the Clang Tool, creating a new FrontendAction (explained below)</div>
<div> int result = Tool.run(newFrontendActionFactory<ExampleFrontendAction>());</div>
<div><br>
</div>
<div> cout << "\nFound " << numFunctions << " functions declarations.\n" << "Found " << numVariables << " variable declarations.\n" << "Found " << numFuncCalls << " function calls.\n" ;</div>
<div> APIs.close();</div>
<div><span class="Apple-tab-span" style="white-space:pre"></span>REPORT.close();</div>
<div> return result;</div>
<div>}</div>
<div><br>
</div>
<br>
<p></p>
<p>The problem is in the Visit functions of the ASTVsitor. I dont know how to get the main file's id. I have seen some implementations in your archive mailing list but nothing looks like mine. </p>
<p><br>
</p>
<p>Thank you</p>
<p><br>
</p>
</div>
</body>
</html>