一、概述

上一篇文章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. 把System.Drawing.Image对象img,在页面的Image控件上显示出来

    1.保存到本地,然后调用. //定义文件名    string iname = DateTime.Now.ToString("yyMMddhhmmss"); //保存到服务器,b是 ...

  2. fckeditor 数据库 取值 显示

    用fckeditor把html代码存到数据库中,取出来显示的时候用什么控件呢?用Literal  或  Label  控件.

  3. spring开发Eclipse需要做设置

    1. 统一工作空间的编码,选择UTF-8 2. 把创建JSP页面的编码修改UTF-8 3. 重新配置Tomcat服务器 * 先配置Tomcat服务器 * 选择服务器 --> open --> ...

  4. iOS.Book.Effective Objective-C 2.0

    1. 中文翻译版 (更新中) https://github.com/HagerHu/effective-objective-c-2.0 2. Book的主页 和 代码主页 http://www.eff ...

  5. 设计规范VS设计创造力,谁更胜一筹?

    设计规范和设计创造力哪个更重要?这是一个颇具争议性的话题.如果是3年前问我这个问题我会毫不犹豫的选择设计创造力,毫无疑问,一个好的设计创造力真的是可以让人像打了鸡血一样疯狂. 原来在上大学的时候,我就 ...

  6. centos6.5 redis 安装配置及java调用

    1.安装gcc 执行命令  yum install gcc 2. 安装ruby环境 yum install ruby yum install rubygems gem install redis 下载 ...

  7. centos6.5 设置ssh无密码登录

    :关闭防火墙 vim /etc/selinux/config 把SELINUX=enforcing修改为SELINUX=disabled   A机器root连接B机器root用户 (root用户登录) ...

  8. Devexpress VCL Build v2014 vol 14.2.1 beta发布

    已经快到2015 年了. 14.2.1 beta 才出来了. 还好,有一些新东西. 官网地址 VCL Gauge Control Designed to clearly convey informat ...

  9. 网站SEO优化的方法

    网站SEO优化的方法: 1.url静态化和规范化:url中都去掉了index.php这样的后缀网址形式,目的就是让网站的层级更浅,获得的权重更高 代码中可以使用urlrewrite重写. 2.域名30 ...

  10. 2018.09.30 bzoj2288:生日礼物(贪心+线段树)

    传送门 线段树经典题目. 每次先找到最大子段和来更新答案,然后利用网络流反悔退流的思想把这个最大字段乘-1之后放回去. 代码: #include<bits/stdc++.h> #defin ...