使用Clang查找If-Conditions

时间:2014-08-31 10:19:33

标签: c++ parsing clang abstract-syntax-tree llvm-clang

我正在尝试使用Clang在C代码中找到if条件。

到目前为止我学到的是使用HandleTopLevelDecl()找到声明。

我现在要做的是找到一个类似于HandleTopLevelDecl()但处理If-Conditions的函数。

我的问题是,我正走在正确的道路上吗?有没有可以做到这一点的功能?

如果没有,你建议我做什么?

感谢。

2 个答案:

答案 0 :(得分:4)

借助这个精彩的课程:http://swtv.kaist.ac.kr/courses/cs453-fall13

特别是本教程:http://swtv.kaist.ac.kr/courses/cs453-fall13/Clang%20tutorial%20v4.pdf

我已经解决了这个问题。

我需要创建一个 RecursiveASTVisitor 并在访问语句时处理If-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;
    }
};

以下是完整的代码:

#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;
}

答案 1 :(得分:0)

在clang中,各种Stmts和Decls具有特定的功能。对于此特定情况,它将为class TestsContainer(unittest.TestCase): longMessage = True def flow_driver(flow_obj, session=None): test_suite = unittest.TestSuite() test = "" klassname = 'Test_{0}'.format(str.upper(flow_obj[0])) d= {} for service in flow_obj[1]: result= some_function() d['test_service_{0}'.format(service)] = make_test_function(service, result) globals()[klassname] = type(klassname, (TestsContainer,), d) test = unittest.makeSuite(globals()[klassname]) test_suite.addTest(test) return test_suite def make_test_function(description, result): def test(self): #do something return test 。检查IfStmt中是否包含RecusiveASTVisitor.h

RecursiveASTVisitor.h-

VisitIfStmt

clang / AST / StmtNodes.inc-

#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"

这些,一起在类中创建函数#ifndef IFSTMT # define IFSTMT(Type, Base) STMT(Type, Base) #endif IFSTMT(IfStmt, Stmt) #undef IFSTMT