C++解析头文件-Qt自动生成信号定义
一、概述
上一篇文章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自动生成信号定义的更多相关文章
- C++解析头文件-Qt自动生成信号声明
目录 一.瞎白话 二.背景 三.思路分析 四.代码讲解 1.类图 2.内存结构声明 3.QtHeaderDescription 4.私有函数讲解 五.分析结果 六.下载 一.瞎白话 时间过的ZTMK, ...
- 用shell脚本新建shell文件并自动生成头说明信息
目标: 新建文件后,直接给文件写入下图信息 代码实现: [root@localhost test]# vi AutoHead.sh #!/bin/bash#此程序的功能是新建shell文件并自动生成头 ...
- 用shell脚本新建文件并自动生成头说明信息
目标: 新建文件后,直接给文件写入下图信息 代码实现: [root@localhost test]# vi AutoHead.sh #!/bin/bash #此程序的功能是新建shell文件并自动生成 ...
- Eclipse中R文件不能自动生成
R文件不能自动生成主要是因为编译有错误,这时你想什么办法都是没有用的,clean, fix properties,都不是从根上解决问题. R文件主要是自动生成资源文件的id的,里边静态子类 ...
- 安装Ruby、Sass在WebStrom添加Watcher实现编辑scss文件时自动生成.map和压缩后的.css文件
前言 这段时间一直在看Bootstrap,V3官方直接提供了Less版本的源码,就先将Less学完了,很简单的语法,学习写Demo都是在Webstorm里写的,配置了Watcher自动编译(详见< ...
- R.java文件无法自动生成的问题
如果出现R.java文件无法自动生成的问题,同时Console窗口提示下列信息: Android requires compiler compliance level 5.0 or 6.0. Foun ...
- webstorm创建js文件时自动生成js注释
设置webstorm创建js文件时自动生成js注释 settings--Editor--File and Code Temlates 黑色框框里的内容自己填写上去,以下是参考的代码块: /** * @ ...
- Qt自动生成.rc文件并配置对应属性 程序图标 版本 描述等
Qt项目配置文件pro里需要如下配置,进行qmake,build后会自动生成.rc文件,并将对应的信息写入文件中 VERSION = 1.0.0.1 RC_ICONS = "http.ico ...
- sublime打开文件时自动生成并打开.dump文件
GBK Encoding Support 没有安装前打开ASNI格式编码文件会乱码,安装成功重启则可以打开正常 关于.dump文件生成的解释: 当打开一个非utf-8格式且包含汉字的文件时,subli ...
随机推荐
- Thread(线程)和ThreadPool(线程池) Thread回调与返回值
Thread(线程) Thread开启线程:接收一个参数 TestClass tc = new TestClass(); //没有返回值,有一个object类型的参数的委托:两种写法. Paramet ...
- C#控制台进度条(Programming Progress bar in C# Consle application)
以下代码从Stack Overflow,觉得以后会用到就收藏一下,我是辛勤的搬运工,咿呀咿呀哟- 1.showing percentage in .net console application(在. ...
- 怎样完整地离线更新并升级基于 Debian 的操作系统
不久之前我已经向你展示了如何在任意离线的 Ubuntu 和 Arch Linux 操作系统上安装软件. 今天,我们将会看看如何完整地离线更新并升级基于 Debian 的操作系统. 和之前所述方法的不同 ...
- [远程] windows 2008 server设置了共享文件夹,并且共享给了everyone,但是还是无法访问,怎么解决呢?
还需要设置另外一个地方,将用户加到MSAppAccess这个组里去
- Linux的简单介绍和开发基本运维时候用到的命令
先简单介绍下Linux文件夹目录 1./ linux下的根目录 实际上等同于window的我的电脑点进去 2./etc /usr 一个是系统配置文件存放的地方,一个是系统资源(应用程序)放的地方这俩文 ...
- VS快捷键以及Reshaper快捷键
VS快捷键: Resharper 快捷键(此图是保存他人的[具体是谁忘记了]): 参考: http://msdn.microsoft.com/zh-cn/library/da5kh0wa.aspx
- 提高搜狗SR值和关键词排名
凭借“输入法-浏览器-搜索”三级火箭战略,搜狗搜狗使用率已超过10%,并成功挤掉谷歌成为国内第二大搜索引擎服务提供商.随着搜狗的快速发展,越来越多的站长将目光投向针对搜狗搜索的关键词优化. 大家都知道 ...
- Django-组件
https://www.cnblogs.com/yuanchenqi/articles/8034442.html
- java判断字符串是否为数字,包括负数
/** * 判断是否为数字,包含负数情况 * @param str * @return */ private boolean isNumeric(String str){ Boolean flag = ...
- Linux学习--2
字符串 字符串可以用单引号,也可以用双引号,也可以不用引号.单双引号的区别跟PHP类似 单引号字符串的限制:单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的:单引号字串中不能出现单引号(对 ...