M.Nour
M.Nour

Reputation: 95

Find If-Conditions using Clang

I'm trying to find the if-conditions in a C-code using Clang.

What I've learned till now is to find the declarations using HandleTopLevelDecl().

What I'm trying to do now is to find a function that is similar to HandleTopLevelDecl() but handles the If-Conditions.

My question is, am I on the right path? is there a function that can do this?

And if not, what do you advice me to do?

Thanks.

Upvotes: 1

Views: 3619

Answers (2)

Shraiysh
Shraiysh

Reputation: 177

There are specific functions in clang for all kinds of Stmts and Decls. For this particular case, it is going to be VisitIfStmt. Check IfStmt being included in RecusiveASTVisitor.h.

RecursiveASTVisitor.h -

#define STMT(CLASS, PARENT)                                                    \
bool WalkUpFrom##CLASS(CLASS *S) {                                           \
  TRY_TO(WalkUpFrom##PARENT(S));                                             \
  TRY_TO(Visit##CLASS(S));                                                   \
  return true;                                                               \
}                                                                            \
bool Visit##CLASS(CLASS *S) { return true; }
#include "clang/AST/StmtNodes.inc"

clang/AST/StmtNodes.inc -

#ifndef IFSTMT
#  define IFSTMT(Type, Base) STMT(Type, Base)
#endif
IFSTMT(IfStmt, Stmt)
#undef IFSTMT

These, together create the function VisitIfStmt(IfStmt*) in the class.

Upvotes: 0

M.Nour
M.Nour

Reputation: 95

With the help of this awesome course: http://swtv.kaist.ac.kr/courses/cs453-fall13

Specially this tutorial: http://swtv.kaist.ac.kr/courses/cs453-fall13/Clang%20tutorial%20v4.pdf

I have solved the problem.

I needed to create a RecursiveASTVisitor and handle the If-Statements while visiting the Statements.

class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
{
public:
    bool VisitStmt(Stmt *s) {

        // Search for If-Statements

        if(isa<IfStmt>(s))
        {
            cerr << "Found IF" << endl;
        }

        return true;
    }

    bool VisitFunctionDecl(FunctionDecl *f) {
        // Print function name
        cerr << f->getNameAsString().c_str() << endl;

        return true;
    }
};

And here are the complete code:

#include <cstdio>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <utility>

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/FileManager.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/ParseAST.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Rewrite/Frontend/Rewriters.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/raw_ostream.h"

using namespace clang;
using namespace std;


// CompilerInstance
CompilerInstance TheCompInst;

    class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor>
    {
    public:
        bool VisitStmt(Stmt *s) {

            // Search for If-Statements

            if(isa<IfStmt>(s))
            {
                SourceManager &srcmgr = TheCompInst.getSourceManager();

                SourceLocation startLocation = s->getLocStart();
                unsigned int start_lineNum = srcmgr.getExpansionLineNumber(startLocation);

                cerr << "Found IF @ Line: " << start_lineNum << endl;
            }

            return true;
        }

        bool VisitFunctionDecl(FunctionDecl *f) {
            // Print function name
            cerr << f->getNameAsString().c_str() << endl;

            return true;
        }
    };

class MyASTConsumer : public ASTConsumer
{
public:
    MyASTConsumer()
        : Visitor() //initialize MyASTVisitor
    {}

    virtual bool HandleTopLevelDecl(DeclGroupRef DR) {
        for (DeclGroupRef::iterator b = DR.begin(), e = DR.end(); b != e; ++b) {
            // Travel each function declaration using MyASTVisitor
            Visitor.TraverseDecl(*b);
        }
        return true;
    }

private:
    MyASTVisitor Visitor;
};


int main(int argc, char *argv[])
{
    if (argc != 2) {
        llvm::errs() << "Usage: kcov-branch-identify <filename>\n";
        return 1;
    }

    // Diagnostics manage problems and issues in compile 
    TheCompInst.createDiagnostics(NULL, false);

    // Set target platform options 
    // Initialize target info with the default triple for our platform.
    TargetOptions *TO = new TargetOptions();
    TO->Triple = llvm::sys::getDefaultTargetTriple();
    TargetInfo *TI = TargetInfo::CreateTargetInfo(TheCompInst.getDiagnostics(), TO);
    TheCompInst.setTarget(TI);

    // FileManager supports for file system lookup, file system caching, and directory search management.
    TheCompInst.createFileManager();
    FileManager &FileMgr = TheCompInst.getFileManager();

    // SourceManager handles loading and caching of source files into memory.
    TheCompInst.createSourceManager(FileMgr);
    SourceManager &SourceMgr = TheCompInst.getSourceManager();

    // Prreprocessor runs within a single source file
    TheCompInst.createPreprocessor();

    // ASTContext holds long-lived AST nodes (such as types and decls) .
    TheCompInst.createASTContext();

    // A Rewriter helps us manage the code rewriting task.
    Rewriter TheRewriter;
    TheRewriter.setSourceMgr(SourceMgr, TheCompInst.getLangOpts());

    // Set the main file handled by the source manager to the input file.
    const FileEntry *FileIn = FileMgr.getFile(argv[1]);
    SourceMgr.createMainFileID(FileIn);

    // Inform Diagnostics that processing of a source file is beginning. 
    TheCompInst.getDiagnosticClient().BeginSourceFile(TheCompInst.getLangOpts(),&TheCompInst.getPreprocessor());

    // Create an AST consumer instance which is going to get called by ParseAST.
    MyASTConsumer TheConsumer;

    // Parse the file to AST, registering our consumer as the AST consumer.
    ParseAST(TheCompInst.getPreprocessor(), &TheConsumer, TheCompInst.getASTContext());

    return 0;
}

Upvotes: 4

Related Questions