栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

使用clang获取代码中的全局变量、函数(名称,参数,返回值)、结构体信息

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

使用clang获取代码中的全局变量、函数(名称,参数,返回值)、结构体信息

1.下载clang源码

本人使用的为clang10.0,visual studio版本为2017(亲测2019会有问题)
clang源码下载地址为 https://releases.llvm.org/download.html#10.0.0

2.编写clang插件

1.解压刚才的源码,进入到llvmtoolsclangtoolsextra目录下,创建文件夹,为自己的项目名称。

2.进入到自己项目名称的文件夹,将自己写好的c文件和h文件放到此文件夹中。新建文件CMakeLists.txt

3.编写CMakeLists.txt,规则见图

4.返回上一级目录,即extra这一层,打开此层的CMakeLists.txt,结尾加入:

3.下载cmake

1.cmake下载地址https://cmake.org/download/
2.下载64位版本

3.傻瓜安装,记得加入到环境变量中

4.使用cmake进行编译(cmake编译依赖python解释器,记得安装python)

1.打开cmake,选择clang的源码目录和编译目录

2.选择visual stdio版本(亲测clang10.0 visual stdio2019 无法编译通过,请使用visual stdio2017)

3.点击配制,点击生成

4.生成完成后,即可在编译目录看见相应的vc工程(双击LLVM.sln。打开工程)

5.在Clang executables下可以发现自己的工程

4.ASTMatcher

1.ASTMatcher类似于正则表达式,书写规则参考官网。很详细https://clang.llvm.org/docs/LibASTMatchersReference.html
2.我们即使用ASTMatcher来匹配所有的全局变量、函数(名称,参数,返回值)、结构体信息

如varDecl为变量,hasGlobalStorage可以筛选全局变量。

5.处理全局变量

1.获取到了全局变量节点,接下来主要调用clang的接口获取全局变量的名称,类型,维度,初值等信息存储到我们自定义的数据结构中。

VariableInfoStruct variableInfoStruct;
	
	std::string nameStr = varDeclNode->getNameAsString();
	std::string initValueStr = "";
	std::string fileName = getNodePath(varDeclNode->getLocation(), Result);
	auto firstDeclNode = varDeclNode->getFirstDecl();
	std::string firstDeclPath = getNodePath(firstDeclNode->getLocation(), Result);
	variableInfoStruct.hPath =
		strcpy(new char[firstDeclPath.length() + 1], firstDeclPath.data());
	variableInfoStruct.path =
		strcpy(new char[fileName.length() + 1], fileName.data());
	variableInfoStruct.name =
		strcpy(new char[nameStr.length() + 1], nameStr.data());
	variableInfoStruct.nodeLocInfo = getLineNumInfo(varDeclNode->getSourceRange(), Result.Context);
	
	std::string typeStr = varDeclNode->getType()
		.getLocalUnqualifiedType()
		.getCanonicalType()
		.getAsString();
	QualType nodeType = varDeclNode->getType();
	// std::cout << varDeclNode->getType().getTypePtr()->getTypeClassName();
	const Type *type = varDeclNode->getType().getTypePtr();
	std::string name = clang::QualType(type, 0).getAsString();
	// std::cout << nodeType.getCanonicalType().getAsString() << "n";
	dealType(typeStr, nodeType, &variableInfoStruct);
	
	const Expr *initExpr = varDeclNode->getAnyInitializer();
	
	std::vector initAstStructVector;
	dealInitValue(initExpr, &initValueStr, Result, &initAstStructVector);
	variableInfoStruct.initValue =
		strcpy(new char[initValueStr.length() + 1], initValueStr.data());
	variableInfoStruct.initAstStruct = initAstStructVector;
	cfile->globalVars.push_back(variableInfoStruct);
6.函数

1.获取到了函数节点,接下来主要调用clang的接口获取函数的名称,参数类型,参数名称,返回值名称,返回值类型等信息存储到我们自定义的数据结构中。

 const FunctionDecl *firstDeclNode = functionDeclNode->getFirstDecl();
	std::string firstDeclFilePath = getNodePath(firstDeclNode->getLocation(), Result);
	FunctionInfoStruct functionInfoStruct;
	std::string fileName = getNodePath(functionDeclNode->getLocation(), Result);
	functionInfoStruct.path = strcpy(new char[fileName.length() + 1], fileName.data());
	functionInfoStruct.hPath = strcpy(new char[firstDeclFilePath.length() + 1], firstDeclFilePath.data());
	std::string nameStr = functionDeclNode->getNameAsString();
	std::string typeStr = functionDeclNode->getReturnType().getAsString();
	functionInfoStruct.name = strcpy(new char[nameStr.length() + 1], nameStr.data());
	functionInfoStruct.type = strcpy(new char[typeStr.length() + 1], typeStr.data());
	functionInfoStruct.nodeLocInfo = getLineNumInfo(functionDeclNode->getSourceRange(), Result.Context);
	functionInfoStruct.paraCount = functionDeclNode->getNumParams();

	unsigned int paraNum = functionDeclNode->getNumParams();
	if (paraNum > 0) 
	{
		for (int i = 0; i < paraNum; i++)
		{
			VariableInfoStruct variableInfoStruct;
			std::string nameStr = functionDeclNode->getParamDecl(i)->getNameAsString();
			variableInfoStruct.name = strcpy(new char[nameStr.length() + 1], nameStr.data());

			
			const clang::ParmVarDecl *paramDecl = functionDeclNode->getParamDecl(i);
			QualType parType = paramDecl->getType();
			QualType parLocalUnqualifiedType = parType.getLocalUnqualifiedType();
			QualType parCanonicalType = parLocalUnqualifiedType.getCanonicalType();
			std::string typeStr = parCanonicalType.getAsString();

			
			const Type *type = functionDeclNode->getParamDecl(i)->getType().getTypePtr();
			clang::SourceRange srcRange = functionDeclNode->getParamDecl(i)->getSourceRange();
			variableInfoStruct.nodeLocInfo = getLineNumInfo(srcRange, Result.Context);

			
			QualType nodeType = functionDeclNode->getParamDecl(i)->getType();
			if (type->getTypeClass() == 8) {
				const DecayedType *DT = type->getAs();
				type = DT->getOriginalType().getTypePtr();
				nodeType = DT->getOriginalType();
			}
			dealType(typeStr, nodeType, &variableInfoStruct);
			functionInfoStruct.paras.push_back(variableInfoStruct);
		}
	}
	cfile->functions.push_back(functionInfoStruct);
7.结构体

1.获取到了结构体节点,接下来主要调用clang的接口获取结构体的名称,成员变量等信息存储到我们自定义的数据结构中。

if (varRecordDeclNode->field_begin() != varRecordDeclNode->field_end())
	{
		
		StructInfo structInfo;
		structInfo.nodeLocInfo = getLineNumInfo(varRecordDeclNode->getSourceRange(), Result.Context);
		std::string nameStr = "";
		std::string qualifier = "";

		
		std::string anonymousName = getAnonymousName(varRecordDeclNode, Result);
		if (!anonymousName.empty()) {
			nameStr = anonymousName;
		}
		if (nameStr.empty() && varRecordDeclNode->getTypedefNameForAnonDecl()) {
			
			nameStr = varRecordDeclNode->getTypedefNameForAnonDecl()->getNameAsString();
		}
		if (nameStr.empty()) {
			
			nameStr = varRecordDeclNode->getNameAsString();
		}
		else {
			qualifier = "typedef";
		}

		std::string structType = "";
		if (varRecordDeclNode->isStruct()) {
			structType = "struct";
		}
		else {
			structType = "union";
		}

		structInfo.type = strcpy(new char[structType.length() + 1], structType.data());
		std::string fileName = getNodePath(varRecordDeclNode->getLocation(), Result);
		structInfo.path = strcpy(new char[fileName.length() + 1], fileName.data());
		structInfo.name = strcpy(new char[nameStr.length() + 1], nameStr.data());
		structInfo.qualifier = strcpy(new char[qualifier.length() + 1], qualifier.data());

		
		for (RecordDecl::field_iterator jt = varRecordDeclNode->field_begin(); jt != varRecordDeclNode->field_end(); jt++)
		{
			dealRecordField(&structInfo, jt, Result);
		}

		cfile->structs.push_back(structInfo);

		return (structIdx + 1);
	}
	else
	{
		return structIdx;
	}

本项目完整的代码见https://github.com/BondChang/GetCFileInfo.git。大家有疑问随时联系。一定知无不言。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/512379.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号