一、概述

上一篇文章C++解析头文件-Qt自动生成信号声明我们主要讲解了怎么去解析C++头文件,然后在指定位置插入函数声明,已达到自动化的效果。既然函数声明已经自动插入了,那么函数实现的定义当然也可以做到自动化插入,而且实现起来比头文件插入还要简单,稍微思考下就能得出结论,.cpp文件的复杂程度要远远低于.h文件。

本篇文章我们就来分享下怎么去插入函数定义

二、实现思路

头文件插入函数声明时,我们选择了先分析头文件,并记住关键位置的行号,然后在指定位置插入字符串,本篇文章我们还是沿用之前的套路,先分析.cpp文件中的所有函数,并记录在内存中,当我们插入新的函数时,我们只需要找到我们要插到哪个函数的下边,或者插入到所有函数之下的行号,执行插入操作即可。

这里有一个很重要的问题,我们怎么知道上一个函数是谁?这个就是函数定义插入的关键所在。

答案:通过分析头文件后的内存结构来获取。既然我们分析了头文件中所有的类,而且类中的函数和作用域我们都有存储,并且记录了所有的行号,那我们只需要找到指定作用域(或者上一个作用)的最后一个函数即可,这就是我们要插入的位置,当我们在实现文件中寻找行号时,只需要找到这个函数的最后一个行即可。

本篇文章是继上一篇文章C++解析头文件-Qt自动生成信号声明的后续,本篇文章的代码也是前一篇博客的完善,而且结构有了一定的修改。

三、代码讲解

1、类图

讲述代码之前,我们先把修改过后的类图贴上,更简洁。

  • QtGrammaAnalusis:对外接口类
  • QtDescription:头文件分析类基类,提供一些基础操作,包含了一个自己的指针,主要是头文件QtHeaderDescription和QtCppDescription可以相互访问
  • QtHeaderDescription:头文件分析类
  • QtCppDescription:实现文件分析类

2、QtCppDescription

本篇文章的细节代码比较少,因此这里我们稍微讲细一点儿,把关键代码都贴上来。首先看下头文件

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、测试

3.1、测试代码

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.2、实现文件测试结果

3.2、头文件测试结果

四、源代码

需要源代码留邮箱,不提供csdn下载了,麻烦

简书地址文章名称


转载声明:本站文章无特别说明,皆为原创,版权所有,转载请注明:朝十晚八 or Twowords


C++解析头文件-Qt自动生成信号定义的更多相关文章

  1. C++解析头文件-Qt自动生成信号声明

    目录 一.瞎白话 二.背景 三.思路分析 四.代码讲解 1.类图 2.内存结构声明 3.QtHeaderDescription 4.私有函数讲解 五.分析结果 六.下载 一.瞎白话 时间过的ZTMK, ...

  2. 用shell脚本新建shell文件并自动生成头说明信息

    目标: 新建文件后,直接给文件写入下图信息 代码实现: [root@localhost test]# vi AutoHead.sh #!/bin/bash#此程序的功能是新建shell文件并自动生成头 ...

  3. 用shell脚本新建文件并自动生成头说明信息

    目标: 新建文件后,直接给文件写入下图信息 代码实现: [root@localhost test]# vi AutoHead.sh #!/bin/bash #此程序的功能是新建shell文件并自动生成 ...

  4. Eclipse中R文件不能自动生成

       R文件不能自动生成主要是因为编译有错误,这时你想什么办法都是没有用的,clean, fix properties,都不是从根上解决问题.    R文件主要是自动生成资源文件的id的,里边静态子类 ...

  5. 安装Ruby、Sass在WebStrom添加Watcher实现编辑scss文件时自动生成.map和压缩后的.css文件

    前言 这段时间一直在看Bootstrap,V3官方直接提供了Less版本的源码,就先将Less学完了,很简单的语法,学习写Demo都是在Webstorm里写的,配置了Watcher自动编译(详见< ...

  6. R.java文件无法自动生成的问题

    如果出现R.java文件无法自动生成的问题,同时Console窗口提示下列信息: Android requires compiler compliance level 5.0 or 6.0. Foun ...

  7. webstorm创建js文件时自动生成js注释

    设置webstorm创建js文件时自动生成js注释 settings--Editor--File and Code Temlates 黑色框框里的内容自己填写上去,以下是参考的代码块: /** * @ ...

  8. Qt自动生成.rc文件并配置对应属性 程序图标 版本 描述等

    Qt项目配置文件pro里需要如下配置,进行qmake,build后会自动生成.rc文件,并将对应的信息写入文件中 VERSION = 1.0.0.1 RC_ICONS = "http.ico ...

  9. sublime打开文件时自动生成并打开.dump文件

    GBK Encoding Support 没有安装前打开ASNI格式编码文件会乱码,安装成功重启则可以打开正常 关于.dump文件生成的解释: 当打开一个非utf-8格式且包含汉字的文件时,subli ...

随机推荐

  1. 什么是Shell、Shell脚本

    Shell本身是一个用C语言编写的程序,它是用户使用Linux的桥梁.Shell既是一种命令语言,又是一种程序设计语言.作为命令语言,它交互式地解释和执行用户输入的命令:作为程序设计语言,它定义了各种 ...

  2. Redis安装异常解决办法

    官网地址:http://redis.io/ 官网下载地址:http://redis.io/download 1. 下载Redis源码(tar.gz),并上传到Linux 2. 解压缩包:tar zxv ...

  3. IIS6.0创建新网站后,浏览显示需输入用户名和密码

    1.首先我们需要创建一个用于匿名访问的账号. 我的电脑右键,电脑管理->本地用户和组->用户->新用户 注意勾选(用户不能更改密码和密码永不过期这两项)   2.右键新创建的用户-& ...

  4. 移动端input验证只允许有数字 在safari浏览器一直不成功解决

    <input class="lineHeight-30" type="text" onkeyup="value=value.replace(/[ ...

  5. linux下nginx tomcat集群

    集群系统一般通过两台或多台节点服务器系统通过相应的硬件及软件互连,每个群集节点都是运行其自己进程的独立服务器. 这些进程可以彼此通信,对网络客户机来说就像是形成了一个单一系统,协同起来向用户提供应用程 ...

  6. Window 编码 UTF-8 BOM 说明

    UTF-8 不需要 BOM,尽管 Unicode 标准允许在 UTF-8 中使用 BOM.所以不含 BOM 的 UTF-8 才是标准形式,在 UTF-8 文件中放置 BOM 主要是微软的习惯(顺便提一 ...

  7. DB2错误码

    SQL语句成功完成 01xxx SQL语句成功完成,但是有警告 + 未限定的列名被解释为一个有相互联系的引用 + 动态SQL语句用分号结束 + 没有找到满足SQL语句的行 + 用DATA CAPTUR ...

  8. ubuntu系统中安装RoboMongo

    1.下载RoboMongo RoboMongo官网下载链接.选择好相应版本. 2.解压文件 tar -xzf robomongo--linux-x86_64-.tar.gzcd robomongo-0 ...

  9. 构造函数constructor 与析构函数destructor(三)

    (1)构造函数初始化列表: 1 class Test{ 2 int i; 3 public: 4 Test(int vi):i(vi){}//这里的从冒号开始,到右大括号结束,这一段是构造函数初始化列 ...

  10. android 网站上下的 adt 不能显示没有安装的

    问题描述 使用SDK Manager更新时出现问题Failed to fetch URL https://dl-ssl.google.com/android/repository/repository ...