使用clang獲取代碼中的全局變量、函數(shù)(名稱罚拟,參數(shù)台诗,返回值)、結(jié)構(gòu)體信息

1.下載clang源碼

本人使用的為clang10.0赐俗,visual studio版本為2017(親測(cè)2019會(huì)有問題)
clang源碼下載地址為 https://releases.llvm.org/download.html#10.0.0

image.png

2.編寫clang插件

1.解壓剛才的源碼拉队,進(jìn)入到llvm\tools\clang\tools\extra目錄下,創(chuàng)建文件夾阻逮,為自己的項(xiàng)目名稱粱快。


image.png

2.進(jìn)入到自己項(xiàng)目名稱的文件夾,將自己寫好的c文件和h文件放到此文件夾中叔扼。新建文件CMakeLists.txt


image.png

3.編寫CMakeLists.txt事哭,規(guī)則見圖
image.png

4.返回上一級(jí)目錄,即extra這一層瓜富,打開此層的CMakeLists.txt鳍咱,結(jié)尾加入:


image.png

3.下載cmake

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

image.png

3.傻瓜安裝,記得加入到環(huán)境變量中
image.png

4.使用cmake進(jìn)行編譯(cmake編譯依賴python解釋器食呻,記得安裝python)

1.打開cmake流炕,選擇clang的源碼目錄和編譯目錄


image.png

2.選擇visual stdio版本(親測(cè)clang10.0 visual stdio2019 無法編譯通過,請(qǐng)使用visual stdio2017)


image.png

3.點(diǎn)擊配制仅胞,點(diǎn)擊生成
image.png

4.生成完成后每辟,即可在編譯目錄看見相應(yīng)的vc工程(雙擊LLVM.sln。打開工程)


image.png

5.在Clang executables下可以發(fā)現(xiàn)自己的工程
image.png

4.ASTMatcher

1.ASTMatcher類似于正則表達(dá)式干旧,書寫規(guī)則參考官網(wǎng)渠欺。很詳細(xì)https://clang.llvm.org/docs/LibASTMatchersReference.html
2.我們即使用ASTMatcher來匹配所有的全局變量、函數(shù)(名稱椎眯,參數(shù)挠将,返回值)胳岂、結(jié)構(gòu)體信息

image.png

如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)系。一定知無不言饺谬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捂刺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子募寨,更是在濱河造成了極大的恐慌族展,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拔鹰,死亡現(xiàn)場(chǎng)離奇詭異仪缸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)列肢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門恰画,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人瓷马,你說我怎么就攤上這事拴还。” “怎么了欧聘?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵片林,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)费封,這世上最難降的妖魔是什么焕妙? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮弓摘,結(jié)果婚禮上焚鹊,老公的妹妹穿的比我還像新娘。我一直安慰自己韧献,他們只是感情好寺旺,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著势决,像睡著了一般。 火紅的嫁衣襯著肌膚如雪察净。 梳的紋絲不亂的頭發(fā)上袱蜡,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天颤枪,我揣著相機(jī)與錄音,去河邊找鬼虽抄。 笑死,一個(gè)胖子當(dāng)著我的面吹牛独柑,可吹牛的內(nèi)容都是我干的迈窟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼忌栅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼车酣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起索绪,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤湖员,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后瑞驱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體娘摔,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年唤反,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了凳寺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡彤侍,死狀恐怖肠缨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盏阶,我是刑警寧澤怜瞒,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響吴汪,放射性物質(zhì)發(fā)生泄漏惠窄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一漾橙、第九天 我趴在偏房一處隱蔽的房頂上張望杆融。 院中可真熱鬧,春花似錦霜运、人聲如沸脾歇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽藕各。三九已至,卻和暖如春焦除,著一層夾襖步出監(jiān)牢的瞬間激况,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國(guó)打工膘魄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留乌逐,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓创葡,卻偏偏與公主長(zhǎng)得像浙踢,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子灿渴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容