C++解析頭文件-Qt自動生成信號定義

[TOC]html

1、概述

上一篇文章C++解析頭文件-Qt自動生成信號聲明咱們主要講解了怎麼去解析C++頭文件,而後在指定位置插入函數聲明,已達到自動化的效果。既然函數聲明已經自動插入了,那麼函數實現的定義固然也能夠作到自動化插入,並且實現起來比頭文件插入還要簡單,稍微思考下就能得出結論,.cpp文件的複雜程度要遠遠低於.h文件。app

本篇文章咱們就來分享下怎麼去插入函數定義ide

2、實現思路

頭文件插入函數聲明時,咱們選擇了先分析頭文件,並記住關鍵位置的行號,而後在指定位置插入字符串,本篇文章咱們仍是沿用以前的套路,先分析.cpp文件中的全部函數,並記錄在內存中,當咱們插入新的函數時,咱們只須要找到咱們要插到哪一個函數的下邊,或者插入到全部函數之下的行號,執行插入操做便可。函數

這裏有一個很重要的問題,咱們怎麼知道上一個函數是誰?這個就是函數定義插入的關鍵所在。測試

答案:經過分析頭文件後的內存結構來獲取。既然咱們分析了頭文件中全部的類,並且類中的函數和做用域咱們都有存儲,而且記錄了全部的行號,那咱們只須要找到指定做用域(或者上一個做用)的最後一個函數便可,這就是咱們要插入的位置,當咱們在實現文件中尋找行號時,只須要找到這個函數的最後一個行便可。spa

本篇文章是繼上一篇文章C++解析頭文件-Qt自動生成信號聲明的後續,本篇文章的代碼也是前一篇博客的完善,並且結構有了必定的修改。指針

3、代碼講解

一、類圖

講述代碼以前,咱們先把修改事後的類圖貼上,更簡潔。 imagecode

  • QtGrammaAnalusis:對外接口類
  • QtDescription:頭文件分析類基類,提供一些基礎操做,包含了一個本身的指針,主要是頭文件QtHeaderDescription和QtCppDescription能夠相互訪問
  • QtHeaderDescription:頭文件分析類
  • QtCppDescription:實現文件分析類

二、QtCppDescription

本篇文章的細節代碼比較少,所以這裏咱們稍微講細一點兒,把關鍵代碼都貼上來。首先看下頭文件htm

a、類定義

看下接口是否是至關簡單,公有接口是對外暴露的,私有函數主要是解析實現文件,下面讓咱們看下幾個比較重要的函數對象

class QtCppDescription : public QtDescription
{
    Q_OBJECT

public:
    QtCppDescription(QObject * parent);
    ~QtCppDescription();

public:
    virtual void GenerateFuncationCode(FuncType, const QString &, const QString & = "") override;

protected:
    virtual void AnalysisFile() override;
private:
    StatementType GuessType(int);
    void AnalysisOne(int &);

    void AnalysisFunc(int &);

private:
    QList<BaseItem> m_funcations;//函數(變量)列表
};

b、分析一個完整的函數

代碼分析中,當出現*(){這樣的字符串時,咱們認爲是要匹配一個函數了,實際上也確實如此。 當咱們開始匹配函數時,一個函數的結束也就是,函數中的左右花括號成對出現時

以下代碼所示,當咱們匹配完一個函數時,咱們構造了一個BaseItem結構來存儲它,主要是記錄了開始行號、結束行號和函數名稱,並存儲在m_funcations結構中

void QtCppDescription::AnalysisFunc(int & row)
{
    QString code = GenerateString(m_iCurRow, row);
    int rIndex = code.indexOf("(");
    int lIndex = code.lastIndexOf("::", rIndex);
    QString name = code.mid(lIndex + 2, rIndex - lIndex - 2);
    ++row;

    while (row < m_strRowContexts.size())
    {
        QString funcCode = GenerateString(m_iCurRow, row);
        if (funcCode.count("{") == funcCode.count("}"))
        {
            BaseItem item;
            item.start = m_iCurRow;
            item.end = row;
            item.name = name;
            m_funcations.append(item);
            break;
        }
        ++row;
    }
}

記錄函數末尾行號主要是爲了咱們方便插入新代碼。

c、插入代碼

插入函數定義代碼也比較簡單,首先就是根據頭文件分析後的類結構查找到咱們要插在哪一個函數以後,接着咱們去m_funcations結構中去查找相應的對象,獲取咱們要插入的行號,最後進行插入操做便可,是否是有了頭文件的幫主,實現文件插入操做就變得至關簡單啦。

void QtCppDescription::GenerateFuncationCode(FuncType type, const QString & code, const QString & /*= ""*/)
{
    QtHeaderDescription * headerDescrition = dynamic_cast<QtHeaderDescription *>(m_pDescription);
    if (nullptr != headerDescrition)
    {
        const ClassDescription & classDesc = headerDescrition->GetDescription();
        //獲取上一個函數名稱

        int index = type;
        const QMap<int, ScopePiece> & scopeIndexs = classDesc.pieceIndexs;
        while (index >= 0)
        {
            if (scopeIndexs.contains(index) && scopeIndexs[index].funcations.size() != 0)
            {
                break;
            }
            --index;
        }

        if (index == -1)
        {
            return;
        }

        QString preFuncName = scopeIndexs[index].funcations.last().name;
        int r = preFuncName.indexOf("(");
        QString leftName = preFuncName.left(r).trimmed();
        int l = leftName.lastIndexOf(" ");
        QString preBaseName = leftName.mid(l + 1);

        auto iter = std::find_if(m_funcations.begin(), m_funcations.end(), [preBaseName](const BaseItem & item) {
            return item.name == preBaseName;
        });

        if (iter != m_funcations.end())
        {
            int insertRow = iter->end;
            m_strRowContexts.insert(insertRow + 1, code);
            m_bDirty = true;

            AnalysisFile();
        }
    }
}

三、測試

3.一、測試代碼

QtGrammaAnalysis analysis;
QString oldFilePath = fileInfo.absoluteFilePath();
analysis.SetHeaderFile(oldFilePath);
analysis.SetCppFile(oldFilePath.replace(".h", ".cpp"));

analysis.GenerateDefinition("\nvoid test1()\n{\n\t\n}");
analysis.GenerateDeclaration("\tvoid test1();");

analysis.SetScopeType(FT_PROTECT_SLOT);
analysis.GenerateDefinition("\nvoid test1_1()\n{\n\t\n}");
analysis.GenerateDeclaration("\tvoid test1_1();");

analysis.SetScopeType(FT_PUBLIC_SLOT);
analysis.GenerateDefinition("\nvoid test1_2()\n{\n\t\n}");
analysis.GenerateDeclaration("\tvoid test1_2();");

analysis.Save();

3.二、實現文件測試結果

image

3.二、頭文件測試結果

image

4、源代碼

須要源代碼留郵箱,不提供csdn下載了,麻煩 <br><br>

簡書地址文章名稱 <br><br>


轉載聲明:本站文章無特別說明,皆爲原創,版權全部,轉載請註明:朝十晚八 or Twowords


原文出處:https://www.cnblogs.com/swarmbees/p/10793254.html

相關文章
相關標籤/搜索