面向c#的函数调用路径生成方法

文档序号:10654210阅读:261来源:国知局
面向c#的函数调用路径生成方法
【专利摘要】本发明提供一种面向C#的函数调用路径生成方法,包括:通过C#程序中与函数相关的信息,所述信息包括:类、命名空间、数据集信息、参数信息;根据每一函数的调用关系,分别生成每一函数的函数调用关系树,其中所述函数调用关系树的每一节点代表一个函数,且每一节点的子节点代表一个分支,且每一节点的兄弟节点与其父节点为并列关系;根据所有函数的函数调用关系树,组合为C#程序的全局的函数调用关系树本发明提供一种面向C#的函数调用路径生成方法,包括:通过C#程序中与函数相关的信息,所述信息包括:类、命名空间、数据集信息、参数信息;根据每一函数的调用关系,分别生成每一函数的函数调用关系树,其中所述函数调用关系树的每一节点代表一个函数,且每一节点的子节点代表一个分支,且每一节点的兄弟节点与其父节点为并列关系;根据所有函数的函数调用关系树,组合为C#程序的全局的函数调用关系树。
【专利说明】
面向c#的函数调用路径生成方法
技术领域
[0001] 本发明设及计算机技术领域,尤其设及一种面向C#的函数调用路径生成方法。
【背景技术】
[0002] C#作为一种面向对象的高级语言,由于其搭载环境Visual studio功能强大、可视 性强、更新较快,而逐渐成为软件开发中的常用语言。随着微软对Visual Studio的版本更 新,其功能越来越强大,C#作为搭载在改坏境下的高级程序设计语言,集成C++和化va的优 点,逐渐成为开发过程中一种重要语言,C#作为面向对象语言,具有封装、继承和多态等性 质,相较于化va语言,二者在语法上也各有特点。由于VS的功能强大,程序编写过程中已经 规避了大多数的语法错误,但逻辑上的错误,需要程序在运行才能找到。函数调用路径的测 试方法将函数调用和程序的逻辑结构相结合,将代码的分析粒度扩展到函数,既避免了路 径的大规模增长又保证了软件测试充分性[1]。对打吾言进行函数调用路径的测试需要通过 对源代码进行词法语法分析获得静态函数调用路径。Java语言的函数调用路径测试是在基 于Soot的基础上,获取静态函数调用路径。对于C#程序,前者的过程显然过于复杂、繁琐,而 后者在C#程序显然不适用。
[000;3]微软在 Visual Studio2010 中开始引入 DGML(Directed Graph Markup Language),并且在该语言的基础上自动生成依赖关系图等有向图。DGML即有向图标记语 言,是一种完全符合XML格式的语言。随后微软在VS2012版本中引入了代码图功能,代码图 可W清晰地显示代码结构。代码图是一种DGML表示的图,在其DGML文件中详细记录了程序 中的命名空间、类和成员之间的依赖关系信息,虽然代码图本身能够分析C#程序并生成函 数的依赖关系,但是运种依赖关系是包含关系并没有逻辑结构,不能直观的得到程序的执 行过程从而无法用于生成测试用例。目前国内外针对C#程序的测试方法较少,对代码图和 DGML的研究也相对较少。
[0004] 由于C#语言包含类、对象、命名空间、重载、委托等多变而又复杂的形态,给C#程序 的理解和测试带来了很大困难。

【发明内容】

[0005] 针对现有技术中存在的对C#语言多变且复杂导致对C#程序的理解和测试带来了 很大困难的问题,本发明要解决的技术问题是提供一种面向C#的函数调用路径生成方法。
[0006] 为了解决上述问题,本发明实施例提出了一种面向C#的函数调用路径生成方法, 包括:
[0007] 步骤1、通过C#程序中与函数相关的信息,所述信息包括:类、命名空间、数据集信 息、参数信息;
[000引步骤2、根据每一函数的调用关系,分别生成每一函数的函数调用关系树,其中所 述函数调用关系树的每一节点代表一个函数,且每一节点的子节点代表一个分支,且每一 节点的兄弟节点与其父节点为并列关系;
[0009] 步骤3、根据所有函数的函数调用关系树,组合为C#程序的全局的函数调用关系 树。
[0010] 其中,所述步骤1具体包括:从DGML文件中获取程序所有的类;从DGML文件中获取 类的所有函数;将类自动生成构造函数。
[0011] 其中,所述步骤2中具体包括:
[0012] 步骤21、对每个成员函数进行分析,获取成员函数的执行语句;
[0013] 步骤22、对执行语句进行分析W确定判断每条语句是否有函数调用,W确定该执 行语句是否存在分支结构;如果存在分支结构,获取分支结构的方法体,然后对方法体里的 每条语句进行分析判断是否还存在函数调用,如果是则将被调用函数的信息加入到函数调 用关系树中。
[0014] 其中,所述步骤22具体包括:
[0015] 步骤221、判断执行语句中是否有函数调用,如果有则将函数调用顺序、调用的函 数添加到列表中;
[0016] 步骤222、判断执行语句中是否有控制关键字,如果有则确定其中的第一个被调用 函数W获取函数调用的顺序,并根据函数调用的顺序依次将函数添加到列表中;
[0017] 步骤23、生成每一函数的S元组T(M,R,S);其中,M表示函数集合;R表示函数的调 用顺序关系<顺序节点,当前节点,分支节点〉表示顺序结构为树的左孩子,分支结构为树的 右孩子;S表示源函数也是函数调用关系树的头节点;
[0018] 步骤24、根据所述每一函数的=元组生成每一函数的函数调用关系树。
[0019] 本发明的上述技术方案的有益效果如下:上述方案中提出了一种面向C#的函数调 用路径生成方法,其结合VS下的代码图功能得到函数及函数的依赖关系信息对源代码进行 分析,采用树结构存储函数的依赖关系和逻辑结构,W此获取每一个函数的函数调用关系 树;然后将程序中所有的函数调用关系树进行组合W得到全局的函数调用关系树。同时通 过本发明实施例中的举例说明可W看出,本发明实施例的方法是可行的,能够得到C#程序 的函数调用路径,有助于开发人员对软件系统的理解W及测试人员进行基于函数调用路径 的测试。
【附图说明】
[0020] 图1为本发明实施例中的DGML的描述图;
[0021] 图2为本发明实施例中的一个举例说明的函数调用关系图;
[0022] 图3为本发明实施例中的另一个举例说明的函数调用关系图;
[0023] 图4为根据图3所示的函数调用关系生成的函数调用关系树。
【具体实施方式】
[0024] 为使本发明要解决的技术问题、技术方案和优点更加清楚,下面将结合附图及具 体实施例进行详细描述。
[0025] 软件系统被修改或扩充后,为了验证对软件的修改是否达到预期的目的,并且没 有引入新的错误而重复进行的测试称为回归测试。在实际测试的回归测试中,由于测试人 员不了解程序的内部结构,所用的测试方法就是全部重测,但是在大中型软件系统中的路 径数目急剧增大,全部重测往往会带来高昂的代价。因此研究人员提出了面向函数调用路 径的思想获取函数的调用路径,可W快速获取与该函数相关的路径,从而进行有针对性的 测试,有利于生成测试用例。具体请参考:ZHANG Zhihua,MU Yongmin.Based on the path to override the generated function calls Research[J].ACTA ELECTRONICA SINICA, 2010,138(8):1808-1811。
[00%] RegressiontestCl.O作为自主开发的基于函数调用路径的测试工具,通过该工具 可W获取C语言的全局静态路径集和动态函数调用路径;具体请参考张志华,牟永敏.基于 函数调用的路径覆盖生成技术研究[J].电子学报,2010,38(8): 1808-1811。该方法具体为:
[0027] 首先对被测的源代码进行静态分析,生成包含代码内部控制逻辑的函数调用关系 图,从而获取静态的函数调用路径;具体请参考:Yuhui Z肥NG,Yongmin Mu, Zhihua ZHANG..Rearch on the Static Function Call Path Generating Automcatically[C] .The 2nd IEEE International Conference on Information Management and Engineering. Chengdu, 2010.1~5;
[0028] 对被测程序进行插装,确定一组测试用例,在程序的执行中获取动态的函数调用 序列;具体请参考:牟永敏,姜智巧,张志华.面向C程序插装的路径提取[J].计算机工程与 应用.2011(01)。
[0029] 对于面向对象语言由于其语法特点,使用面向过程的函数调用路径的生成方法: 开发词法分析器、语法分析器等来静态分析程序源码,获取函数的函数调用路径,明显会增 大工作量。因此在生成化va的函数调用路径时,研究人员提出了基于Soot来生成化va的函 数调用路径,具体请参考:朱绪利,牟永敏,张志华.基于Soot控制流图的函数调用路径分析 [J].数据通信,2012年第一期。在该方法中,通过Soot编译化框架将化va信息生成JimpleS 地址文件,从而确定多态调用点信息,按照多态唯一性静态分析算法,确定多态唯一性信 息,提取函数间关联信息,定义函数调用树,并分析单个函数调用关系树与程序函数调用图 之间的关系,通过组合算法生成程序的函数调用关系图。
[0030] 虽然研究人员先后提取了C、C++Java版本的函数调用路径,但方法不能通用,且 因 C#语言多变而又复杂,之前没有进行相关研究。
[0031] 发明人通过研究发现,Visual studio(简称VS)生成的代码图的DGML文件详细记 录了函数之间的依赖关系,运为生成C#的函数调用路径提供了帮助。使用Visual Studio可 W生成代码内部的关系图即代码图,直观显示源代码中的复杂关系。其中,得到的代码图就 在代码编辑器的右侧,运样就能在编码的时候看到代码的结构。该关系图是用DGML语言描 述的,DGML的描述图如图1所示。
[00创在DGML描述语言中,主要描述程序内部信息的标签是Node、Links和 IdentifierAliases:
[0033] 其中IdentifierAliases主要是对函数和类W别名标记,运里的别名对应阿拉伯 数字;除此之外还记录了程序的命名空间和数据集W及函数的参数信息,即使是重名的函 数也可W区分。函数参数信息一般在Id属性中WOverloadin评arameters备注。
[0034] 区别于Identif ierAliases ,Node标签记录的信息函数和类的信息,例如:类 (CodeSchema_class)、方法(CodeSchema_Method)、构造函数(IsConstructor=" true")、接 口(〔0(165。1161]1日_1]116处日。6)、委托(〔0(165。1161]1日_〇616邑日16)、名称化日661)、函数类型 (I sPub I i C)等。Node标签会自动生成类中没有声明的构造成员方法。
[0035] Links标签记录函数之间的关系信息,包括:类与成员函数的包含(Contains)、调 用(CodeSchema_CalIs)、继承(InheritsFrom)、接口 的实现(Implements) W及委托等。 Source和化rget,表示代码图中箭头的起点和终点,也记录了函数中调用与被调用,类与函 数包含和被包含的关系,W及继承中的父类与子类被继承与继承的关系,接口中的继承与 实现的关系。
[0036] VS生成的代码图只有包含关系,没有逻辑结构,对于W下代码:
[0037;
[0038] 可W生成如图2所示的函数调用关系图。
[0039] 针对现有技术中缺少本发明实施例提出了一种面向C#的函数调用路径生成方法, 具体包括:
[0040] 步骤1、W树结构记录函数的调用关系。
[0041] 在C#程序中,可W树形结构来标识函数的调用关系,称为函数调用关系树。在函数 调用关系树中的每一个节点代表一个函数,其孩子代表一个分支;如果函数没有分支,则孩 子代表接下来要执行的函数名;节点的兄弟标识与父节点是并列关系,在程序中用来表示 多条分支。
[0042] 在C#程序中,与函数相关的信息包括:类、命名空间、数据集信息、参数信息;而运 些信息都存储在代码图的DGML文件中。DGML文件W别名作为索引记录函数,运里也可W使 用别名来作为C#函数调用关系树的节点,减少了存储大量的函数信息,可W提高算法的运 行效率。
[0043] 在图3所示的函数调用路径,可W表示为图4所示的函数调用关系树。@6对应函数 Test,@7对应函数f0,@8对应函数n,@9对应函数f2。使用=元组T(M,R,S)来表示调用关系: M表示函数集合;R表示函数的调用顺序关系<顺序节点,当前节点,分支节点〉表示顺序结构 为树的左孩子,分支结构为树的右孩子;S表示源函数也是函数调用关系树的头节点。那么 对于图3相对应的代码:
[0044] M={@6,@7,@8,@9};
[0045] R={(@8,@6,null),(@7,@8,@9),(@7,@9,null)},
[0046] S= {@6};
[0047] 该函数调用关系序列所对应的全局函数调用关系树如图4所示。说明程序中有两 条路径:
[0048] 化thl:@6-〉@8-〉@7
[0049] 化th2:@6-〉@9-〉@7;
[0050] 如前所述的,@9是@8的右孩子也就是兄弟节点;体现的是并列关系。生成的函数调 用关系树即表现了运种结构特征。从S元组中也可W看出@6顺序执行了 @8,但是@8和@9是 并列关系,那么@6和@9也可W是一种顺序结构。而上面程序中的if-else语句正是运种关 系。
[0051 ] 而针对W下的代码:
[0化2]
[00£
[0054] 对于一个带有继承关系的程序来说在,父类为Contact ;Friend和Family为继承了 Con化Ct类的子类;main函数中变量con巧日con2分别调用了子类的方法;化iend和Fami Iy分 别对父类方法进行了重写。但是con4调用了 Family的构造函数,却调用了父类的方法。在代 码图的DGML文件中详细记录了运种函数调用信息,包括@4继承了( Inhe;ritsF;rom)@3, Family继承了Contact类,@5继承了@3,F;riend类继承了Contact类。由此可W看出,如果调 用了父类的方法,DGML会记录(Target)调用了父类的方法,但如果子类对父类进行了重写 后,调用了运个重写方法,DGML会记录(Tar ge t)调用的是子类方法。对于接口,DGML的记录 方法类似。
[0化日]它的函数调用关系树W=元组来表示:
[0化6] 1={@8,@10,@11,@12,@13,@14,@15};其中的@10,@11,@12是〔#程序的代码图自动 为Con化Ct类、Family类、化iend类生成的构造函数。
[0057] R={(@1〇,@8,null),(@12,@10,null),,null,null),(@13,@ 11,null),(@14,@11,null),(@15,@14,null),(@13,@15,null)},
[0化引 S= {(@8)};
[0059] 运里使用<1?37,乂曰1116〉字典的数据结构来存储函数调用关系树,key中存储源函 数,value存储调用关系。对于上面源码中的Main函数,key中存储函数签名:<@8〉; value中 存储调用关系,即被调函数集合List<Method〉。函数的调用关系W-个Struct结构存储, Struct中WS个变量来记录函数调用关系^hildID,ID JrotherID〉。当前节点ID,节点的 左孩子化i IdID用来表示顺序调用,节点的右孩子即兄弟节点化other ID用来表示分支结 构。
[0060] 函数调用关系树的生成算法如下:
[0061;

[0063]
[0064] 2、生成全局函数调用关系树
[0065] 获取程序的入口点,从入口点的函数调用关系树开始,将每一个函数的函数调用 关系树加入到全局的函数调用关系树中。加入的运棵函数调用关系树的叶子节点的左孩子 指向被代替的那个函数的左孩子节点。
[0066] 全局函数调用关系树的生成算法如下:
[0067]
[006引
[0069] 在此基础上生成全局的函数调用路径只需要将函数调用关系树中的兄弟节点使 用同一父节点。根据别名编号从程序的DGML文件中提取函数的相关信息(读取XML文件的过 程)生成带有函数具体信息的函数调用路径。
[0070] 举例说明:
[0071] W下面的源码为例,按照上面的算法进行分析,得到此程序的函数调用路径。如下 所示源码是一个用于加减乘除的运算,Computor类是一个计算器,内部定义了加(Add)减 (Minus)乘(Multiply)除(Divide)方法,W及警告(Warning)方法,当除数为0时,执行警告。 主函数在Program类中,程序的命名空间为Exp,对运个程序进行分析:
[0072]

[007<
[0075] 利用本发明实施例的方法来对源代码和DGML文件进行处理,则根据各个类的各个 函数获取函数调用关系树。W下为Main函数的分析结果:
[0076] @7
[0077] <@8,@7,null〉
[007引 <@14,@8,null>
[0079] <il6,il4,null>
[0080] <@9,@16,null>
[0081 ] <@17,@9,null>
[0082] <null,il7,il0>
[0083] <null,ilO,null>
[0084] 从上面可WMain函数(即@7)分别调用了 @8、@14、@16、@9、@17、@10,其所对应的函 数分别是ComputoH )(代码图自动为Computor类生成的构造函数)、NumA、NumB、Add()、 胖曰^1叫〇、山乂1(16()。根据本发明实施例中的左孩子为顺序结构、右孩子为分支结构的原 贝1J,可W确定@17和@10是兄弟节点;运一点与程序的逻辑结构相同。
[0085] 进一步的,分析Computor类的Add方法得到函数调用关系树:
[0086] @9
[0087] <014,@9,null)
[008引 <@16,@14,null〉
[0089] 根据^上现实的可知,Add函数(gp@9)调用了@14和@16,分别是属性NumA和NumB, 且它们之间是顺序结构;这与程序的内部信息相同。程序中六(1(1、]?;[11113、]?11;^1口17、(1;[¥1(16的 调用结构类似,获取的函数调用关系树类似。
[0090] 将局部的函数调用关系树组合成全局的函数调用关系树,获取到的函数调用路径 如下:
[0091] Pathl
[0092] @7:E邱.Program.CodeSchema_Method<Main(System.StringArray Rank二1)〉
[0093] @8: E邱? Computor ? CodeSchema_Method<Computor 0〉
[0094] @14: E邱? Computor ? (^社目客诚目巧过-口的口目別式曲欄八〉
[00 巧]@16: E邱? Computor ? CodeSchema_Propei'ty<NumB〉
[0096] @9:E邱?Computor?CodeSchema_Method<Add()〉
[0097] @14: E邱? Computor ? (^社目客诚目巧过-口的口目別式曲欄八〉
[0098] @16: E邱? Computor ? CodeSchema_Propei'ty<NumB〉
[0099] @17:E邱?Computor?CodeSchema_Method<Warning()〉
[0100] Path2
[0101] @7:Exp. Program.CodeSchema_Method〈Main(System.StringArray 民ank二I)〉
[0102] @8: E邱? Computor ? CodeSchema_Method<Computor 0〉
[0103] @14: E邱? Computor ? (^社目客诚目巧过-口的口目別式曲欄八〉
[0104] @16: E邱? Computor ? CodeSchema_Propei'ty<NumB〉
[010日]@9:E邱?Computor?CodeSchema_Method<Add()〉
[0106] @14: E邱? Computor ? (^社目客诚目巧过-口的口目別式曲欄八〉
[0107] @16: E邱? Computor ? CodeSchema_Propei'ty<NumB〉
[0108] @10:E邱?Computor?CodeSchema_Method<divide 0〉
[0109] @14: E邱? Computor ? (^社目客诚目巧过-口的口目別式曲欄八〉
[0110] @16: E邱? Computor ? CodeSchema_Propei'ty<NumB〉
[0111] W上是由全局函数调用关系树结合DGML文件中存储的函数信息获取的详细的函 数调用路径;从该路径可知程序中有两条函数调用路径这与程序中的分支结构对应。从结 果可W看出,此程序准确的提取了程序的函数调用路径。
[0112] 由于DGML给出的函数信息准确、详细,程序已经基本可W解决简单的包括继承、接 口、多态相关的程序D
[0113] W上所述是本发明的优选实施方式,应当指出,对于本技术领域的普通技术人员 来说,在不脱离本发明所述原理的前提下,还可W作出若干改进和润饰,这些改进和润饰也 应视为本发明的保护范围。
【主权项】
1. 一种面向C#的函数调用路径生成方法,其特征在于,包括: 步骤1、通过C#程序中与函数相关的信息,所述信息包括:类、命名空间、数据集信息、参 数信息; 步骤2、根据每一函数的调用关系,分别生成每一函数的函数调用关系树,其中所述函 数调用关系树的每一节点代表一个函数,且每一节点的子节点代表一个分支,且每一节点 的兄弟节点与其父节点为并列关系; 步骤3、根据所有函数的函数调用关系树,组合为C#程序的全局的函数调用关系树。2. 根据权利要求1所述的面向C#的函数调用路径生成方法,其特征在于,所述步骤1具 体包括:从DGML文件中获取程序所有的类;从DGML文件中获取类的所有函数;将类自动生成 构造函数。3. 根据权利要求1所述的面向C#的函数调用路径生成方法,其特征在于,所述步骤2中 具体包括: 步骤21、对每个成员函数进行分析,获取成员函数的执行语句; 步骤22、对执行语句进行分析以确定判断每条语句是否有函数调用,以确定该执行语 句是否存在分支结构;如果存在分支结构,获取分支结构的方法体,然后对方法体里的每条 语句进行分析判断是否还存在函数调用,如果是则将被调用函数的信息加入到函数调用关 系树中。4. 根据权利要求1所述的面向C#的函数调用路径生成方法,其特征在于,所述步骤22具 体包括: 步骤221、判断执行语句中是否有函数调用,如果有则将函数调用顺序、调用的函数添 加到列表中; 步骤222、判断执行语句中是否有控制关键字,如果有则确定其中的第一个被调用函数 以获取函数调用的顺序,并根据函数调用的顺序依次将函数添加到列表中; 步骤23、生成每一函数的三元组T(M,R,S);其中,Μ表示函数集合;R表示函数的调用顺 序关系〈顺序节点,当前节点,分支节点〉表示顺序结构为树的左孩子,分支结构为树的右孩 子;S表示源函数也是函数调用关系树的头节点; 步骤24、根据所述每一函数的三元组生成每一函数的函数调用关系树。
【文档编号】G06F9/44GK106020848SQ201610397615
【公开日】2016年10月12日
【申请日】2016年6月7日
【发明人】牟永敏
【申请人】北京信息科技大学, 牟永敏
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1