Source Manager correclty implemented to check in AST visitor if a node belongs in the main input file

Hello ,

As the title states, I have an AST visitor which extracts some information from source files.

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.

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.

I tried to implement it but it doesn’t work. Can you help me? Here is my complete code:

#include “clang/Driver/Options.h”
#include “clang/AST/AST.h”
#include “clang/AST/ASTContext.h”
#include “clang/AST/ASTConsumer.h”
#include “clang/AST/RecursiveASTVisitor.h”
#include “clang/Frontend/ASTConsumers.h”
#include “clang/Frontend/FrontendActions.h”
#include “clang/Frontend/CompilerInstance.h”
#include “clang/Tooling/CommonOptionsParser.h”
#include “clang/Tooling/Tooling.h”
#include “clang/Rewrite/Core/Rewriter.h”
#include “clang/Basic/SourceManager.h”
#include
#include

using namespace std;
using namespace clang;
using namespace clang::driver;
using namespace clang::tooling;
using namespace llvm;

int numFunctions = 0;
int numVariables = 0;
int numFuncCalls = 0;
int append;

ofstream APIs, REPORT;
LangOptions LangOpts;
PrintingPolicy Policy(LangOpts);

//function which checks if the specified file exists or not.
bool fexists(const char *filename)
{
ifstream ifile(filename);
return ifile;
}

class ExampleVisitor : public RecursiveASTVisitor {
private:
ASTContext *astContext; // used for getting additional AST info
public:
explicit ExampleVisitor(CompilerInstance *CI)
: astContext(&(CI->getASTContext()))// directly initialize private members
{
}

bool VisitVarDecl(VarDecl *var)
{
FullSourceLoc FullLocation = astContext->getFullLoc(var->getLocStart());
FileID fileID = FullLocation.getFileID();
SourceManager &SM = astContext->getSourceManager();
FileID MFileID = SM.getMainFileID();
//unsigned int mainFileID = MFileID.getHashValue();
//unsigned int thisFileID = fileID.getHashValue();
//cout << mainFileID << " " << thisFileID << endl;
if (SM.isInMainFile(var->getLocStart())) //checks if the node is in the main = input file.
{
if(var->hasLocalStorage() || var->isStaticLocal ())
{
//var->dump(); //prints the corresponding line of the AST.
numVariables++;
string varName = var->getQualifiedNameAsString();
string varType = var->getType().getAsString();
REPORT << "Variable Declaration: " << varName << " of type " << varType << “\n”;
APIs << varType << “,”;
}
}
return true;
}

bool VisitFunctionDecl(FunctionDecl *func)
{
FullSourceLoc FullLocation = astContext->getFullLoc(func->getLocStart());
FileID fileID = FullLocation.getFileID();
//unsigned int thisFileID = fileID.getHashValue();
//cout << thisFileID << endl;
SourceManager &SM = astContext->getSourceManager();
//FileID MFileID = SM.getMainFileID();
//unsigned int mainFileID = MFileID.getHashValue();
//cout << mainFileID << " " << thisFileID << endl;

if(SM.isInMainFile(func->getLocStart())) //checks if the node is in the main (input) file.
{
string funcName = func->getNameInfo().getName().getAsString();
string funcType = func->getResultType().getAsString();
//func ->dump(); //prints the corresponding line of the AST.
REPORT << “Function Declaration: " << funcName << " of type " << funcType << “\n”;
if (append == 0 && numFunctions == 0)
APIs << funcName <<”:";
else
APIs << “\n” << funcName <<":";
APIs <<funcType << “,”;
numFunctions++;
}
return true;
}

bool VisitStmt(Stmt *st)
{
FullSourceLoc FullLocation = astContext->getFullLoc(st->getLocStart());
FileID fileID = FullLocation.getFileID();
//unsigned int thisFileID = fileID.getHashValue();
SourceManager &SM = astContext->getSourceManager();
if(SM.isInMainFile(st->getLocStart())) //checks if the node is in the main = input file.
{
if (CallExpr *call = dyn_cast(st))
{
numFuncCalls++;
call->dump(); //prints the corresponding line of the AST.
FunctionDecl *func_decl;
if(call->getDirectCallee())
{
func_decl = call ->getDirectCallee();
string funcCall = func_decl->getNameInfo().getName().getAsString();
REPORT << "Function call: " << funcCall << " with arguments ";
APIs << funcCall << “,”;
for(int i=0, j = call->getNumArgs(); i<j; i++)
{
//For each argument it prints its type. The function must be declared otherwise it will return int-for unknown argument type.
APIs << call->getArg(i)->getType().getAsString()<< “,”;
REPORT << call->getArg(i)->getType().getAsString() << ", ";
}
REPORT << “\n”;
}
/*else
{
Expr *expr = call->getCallee();
string exprCall = expr ->getStmtClassName();
REPORT << "Expression call: " << exprCall << " with arguments ";
APIs << exprCall << “,”;
for(int i=0, j = call->getNumArgs(); i<j; i++)
{
//For each argument it prints its type. The function must be declared otherwise it will return int-for unknown argument type.
APIs << call->getArg(i)->getType().getAsString()<< “,”;
REPORT << call->getArg(i)->getType().getAsString() << ", ";
}
REPORT << “\n”;
}
*/
}
}
return true;
}
};

//Creating an ASTConsumer
class ExampleASTConsumer : public ASTConsumer
{
private:
ExampleVisitor *Visitor; // doesn’t have to be private

public:
// override the constructor in order to pass CI
explicit ExampleASTConsumer(CompilerInstance *CI)
: Visitor(new ExampleVisitor(CI))
{ }

// override this to call our ExampleVisitor on the entire source file
virtual void HandleTranslationUnit(ASTContext &Context) {
/* we can use ASTContext to get the TranslationUnitDecl, which is
a single Decl that collectively represents the entire source file */
Visitor->TraverseDecl(Context.getTranslationUnitDecl());
}
};

//Creating a FrontendAction
//This is very similar with the official tutorial of clang about RecursiveASTVisitor
class ExampleFrontendAction : public ASTFrontendAction
{
public://this is from the basic tutorial.
virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI, StringRef file)
{
return new ExampleASTConsumer(&CI); // pass CI pointer to ASTConsumer
}
};

int main(int argc, const char **argv)
{
if (argc < 3)
{
cerr << “usage: " << argv[0] << " --” << endl;
return EXIT_FAILURE;
}

if (!fexists(argv[1]))
{
cerr << “Specified input file does not exist.” << endl;
return EXIT_FAILURE;
}

if (fexists(“API.txt”))
append = 1; //it means will append the file.
else
append = 0;
APIs.open (“API.txt”, ios::out | ios::app);
REPORT.open(“report.txt”);

// parse the command-line args passed to your code
CommonOptionsParser op(argc, argv);

// create a new Clang Tool instance (a LibTooling environment)
ClangTool Tool(op.getCompilations(), op.getSourcePathList());

// run the Clang Tool, creating a new FrontendAction (explained below)
int result = Tool.run(newFrontendActionFactory());

cout << “\nFound " << numFunctions << " functions declarations.\n” << “Found " << numVariables << " variable declarations.\n” << “Found " << numFuncCalls << " function calls.\n” ;
APIs.close();
REPORT.close();
return result;
}

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.

Thank you