1.下載clang源碼
本人使用的為clang10.0赐俗,visual studio版本為2017(親測(cè)2019會(huì)有問題)
clang源碼下載地址為 https://releases.llvm.org/download.html#10.0.0
2.編寫clang插件
1.解壓剛才的源碼拉队,進(jìn)入到llvm\tools\clang\tools\extra目錄下,創(chuàng)建文件夾阻逮,為自己的項(xiàng)目名稱粱快。
2.進(jìn)入到自己項(xiàng)目名稱的文件夾,將自己寫好的c文件和h文件放到此文件夾中叔扼。新建文件CMakeLists.txt
3.編寫CMakeLists.txt事哭,規(guī)則見圖
4.返回上一級(jí)目錄,即extra這一層瓜富,打開此層的CMakeLists.txt鳍咱,結(jié)尾加入:
3.下載cmake
1.cmake下載地址https://cmake.org/download/
2.下載64位版本
3.傻瓜安裝,記得加入到環(huán)境變量中
4.使用cmake進(jìn)行編譯(cmake編譯依賴python解釋器食呻,記得安裝python)
1.打開cmake流炕,選擇clang的源碼目錄和編譯目錄
2.選擇visual stdio版本(親測(cè)clang10.0 visual stdio2019 無法編譯通過,請(qǐng)使用visual stdio2017)
3.點(diǎn)擊配制仅胞,點(diǎn)擊生成
4.生成完成后每辟,即可在編譯目錄看見相應(yīng)的vc工程(雙擊LLVM.sln。打開工程)
5.在Clang executables下可以發(fā)現(xiàn)自己的工程
4.ASTMatcher
1.ASTMatcher類似于正則表達(dá)式干旧,書寫規(guī)則參考官網(wǎng)渠欺。很詳細(xì)https://clang.llvm.org/docs/LibASTMatchersReference.html
2.我們即使用ASTMatcher來匹配所有的全局變量、函數(shù)(名稱椎眯,參數(shù)挠将,返回值)胳岂、結(jié)構(gòu)體信息
如varDecl為變量,hasGlobalStorage可以篩選全局變量舔稀。
5.處理全局變量
1.獲取到了全局變量節(jié)點(diǎn)乳丰,接下來主要調(diào)用clang的接口獲取全局變量的名稱,類型内贮,維度产园,初值等信息存儲(chǔ)到我們自定義的數(shù)據(jù)結(jié)構(gòu)中。
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<InitAstStruct> 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.函數(shù)
1.獲取到了函數(shù)節(jié)點(diǎn)夜郁,接下來主要調(diào)用clang的接口獲取函數(shù)的名稱什燕,參數(shù)類型,參數(shù)名稱竞端,返回值名稱屎即,返回值類型等信息存儲(chǔ)到我們自定義的數(shù)據(jù)結(jié)構(gòu)中。
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());
/* 獲取函數(shù)參數(shù)的類型 */
const clang::ParmVarDecl *paramDecl = functionDeclNode->getParamDecl(i);
QualType parType = paramDecl->getType();
QualType parLocalUnqualifiedType = parType.getLocalUnqualifiedType();
QualType parCanonicalType = parLocalUnqualifiedType.getCanonicalType();
std::string typeStr = parCanonicalType.getAsString();
/* 將函數(shù)參數(shù)的類型轉(zhuǎn)換為Type,方便后續(xù)判斷是否為數(shù)組類型 */
const Type *type = functionDeclNode->getParamDecl(i)->getType().getTypePtr();
clang::SourceRange srcRange = functionDeclNode->getParamDecl(i)->getSourceRange();
variableInfoStruct.nodeLocInfo = getLineNumInfo(srcRange, Result.Context);
/* 說明是Decayed類型,即本來是數(shù)組類型事富,被clang轉(zhuǎn)換成指針類型 */
QualType nodeType = functionDeclNode->getParamDecl(i)->getType();
if (type->getTypeClass() == 8) {
const DecayedType *DT = type->getAs<DecayedType>();
type = DT->getOriginalType().getTypePtr();
nodeType = DT->getOriginalType();
}
dealType(typeStr, nodeType, &variableInfoStruct);
functionInfoStruct.paras.push_back(variableInfoStruct);
}
}
cfile->functions.push_back(functionInfoStruct);
7.結(jié)構(gòu)體
1.獲取到了結(jié)構(gòu)體節(jié)點(diǎn)技俐,接下來主要調(diào)用clang的接口獲取結(jié)構(gòu)體的名稱,成員變量等信息存儲(chǔ)到我們自定義的數(shù)據(jù)結(jié)構(gòu)中统台。
if (varRecordDeclNode->field_begin() != varRecordDeclNode->field_end())
{
/* 說明結(jié)構(gòu)體有成員 */
StructInfo structInfo;
structInfo.nodeLocInfo = getLineNumInfo(varRecordDeclNode->getSourceRange(), Result.Context);
std::string nameStr = "";
std::string qualifier = "";
/* 如果是匿名結(jié)構(gòu)體,則獲取匿名結(jié)構(gòu)體的名稱 */
std::string anonymousName = getAnonymousName(varRecordDeclNode, Result);
if (!anonymousName.empty()) {
nameStr = anonymousName;
}
if (nameStr.empty() && varRecordDeclNode->getTypedefNameForAnonDecl()) {
/* 獲取結(jié)構(gòu)體的typedef名稱 */
nameStr = varRecordDeclNode->getTypedefNameForAnonDecl()->getNameAsString();
}
if (nameStr.empty()) {
/* 直接獲取結(jié)構(gòu)體的名字 */
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());
/* 記錄結(jié)構(gòu)體的field數(shù)量 */
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;
}
本項(xiàng)目完整的代碼見https://github.com/BondChang/GetCFileInfo.git虽另。大家有疑問隨時(shí)聯(lián)系。一定知無不言饺谬。