[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