[cfe-dev] Source Manager correclty implemented to check in AST visitor if a node belongs in the main input file
Georgiou, Andreas via cfe-dev
cfe-dev at lists.llvm.org
Sat Jul 9 12:57:22 PDT 2016
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 <iostream>
#include <fstream>
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<ExampleVisitor> {
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<CallExpr>(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] << " <filename> --" << 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<ExampleFrontendAction>());
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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20160709/f11e36c5/attachment.html>
More information about the cfe-dev
mailing list