我正在尝试使用Clang在C代码中找到if条件。
到目前为止我学到的是使用HandleTopLevelDecl()找到声明。
我现在要做的是找到一个类似于HandleTopLevelDecl()但处理If-Conditions的函数。
我的问题是,我正走在正确的道路上吗?有没有可以做到这一点的功能?
如果没有,你建议我做什么?
感谢。
答案 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
。