本發(fā)明涉及的是一種軟件版本演化對比分析方法,具體地說是一種以diff為基礎(chǔ)的ast軟件版本演化對比分析方法。
背景技術(shù):
軟件版本演化分析,其本質(zhì)都是針對軟件源碼進行差異分析,針對軟件演化分析的方法和源碼差異分析方法,介紹本發(fā)明的技術(shù)背景。
軟件演化分為動態(tài)演化和靜態(tài)演化,動態(tài)演化也稱在線演化,是指在軟件執(zhí)行期間演化,靜態(tài)演化更多的是對軟件版本源碼差異內(nèi)容的一個理解和展示,接下來闡述的軟件版本演化只是針對靜態(tài)演化。主要是介紹的是與源碼差異分析方法相關(guān)的,靜態(tài)演化相關(guān)的軟件版本演化分析方法。
目前,在軟件版本演化分析方面,根據(jù)其分析的粒度主要分為四個分類進行研究,第一個分類是針對源碼的增加、刪除、修改和未改的代碼行數(shù)進行進一步研究。第二個分類是針對增加、刪除、修改和未改的類函數(shù)等語法結(jié)構(gòu)進一步研究,通過將軟件版本的變化分為47種來理解軟件演化的過程,到底是什么決定了軟件演化的走向,其種類劃分的依據(jù)是類函數(shù)等語法結(jié)構(gòu)的屬性參數(shù)和語句的種類,如函數(shù)的參數(shù)改變了是一種變化的種類,語句則有條件、循環(huán)和else語句等。其中比較有代表性的是一種改進的基于ast的軟件演化分析方法,該方法是基于ast編輯距離(levenshteindistance,ld)的方法的改進,基于ast編輯距離(levenshteindistance,ld)方法通常被用于輸入字符串的快速模糊匹配、英文輔助,寫作等領(lǐng)域,是一種經(jīng)典而廣為使用的方法。早在1996年的時候有人將ld算法的思想遷移到源碼的對比,chawathe提出了基于ast的最短編輯距離算法分析分層結(jié)構(gòu)化代碼,假設分層結(jié)構(gòu)化代碼都是對稱的,類函數(shù)等模塊的語法結(jié)點都是一樣的,只是具體屬性有所變化?;诖朔椒ㄋ枷耄岢隽艘环N改進的基于ast的軟件演化分析方法,提高了算法的效率和準確性,將算法的適用范圍拓寬了,不只限于分層結(jié)構(gòu)化代碼。
第三個分類是針對改變和未變的代碼進行視圖顯示,然后進行進一步研究,從文本和軟件工程兩個角度分析,通過完善diff的工作,構(gòu)造了一個vcn(visualcodenavigator),通過視圖顯示演化信息,可視化的理解版本演化規(guī)律,但是vcn只支持c/c++。第四個分類是針對軟件源碼的模型進行研究,模型映射與比較可以用于軟件復用和軟件版本演化分析研究雖然能很好的滿足軟件開發(fā)者的需求,但是需要對軟件版本的模型進行獲取分析,有的軟件版本無法獲取模型,總的來說這個方法操作難度較大。針對每一個方向都有各種實現(xiàn)方式,每一種方式也有各自的優(yōu)缺點。
從這些研究者的研究內(nèi)容看出,雖然軟件版本演化分析算法和源碼的差異分析算法種類繁多,但是大多是從語義的角度切入,基于ast的版本演化對比分析已經(jīng)成為了源碼分析的熱點。相對于原有的靜態(tài)源碼分析,針對整個的源碼版本的整體架構(gòu)的分析算法,演化分析的準確性和效率都不高。
技術(shù)實現(xiàn)要素:
本發(fā)明的目的在于提供一種能提高獲取演化信息的準確率,并能提高軟件版本演化分析效率的基于ast的軟件版本演化對比分析方法。
本發(fā)明的目的是這樣實現(xiàn)的:
步驟一:通過unix的diff命令對兩個軟件版本源碼進行比對分析,根據(jù)分析結(jié)果文件patch獲取代碼行的增加、刪除、改變的情況,將變化的源碼分為三種源碼塊;
步驟二:通過語法分析器獲取兩個軟件版本源碼的ast信息,針對第一步分析出的三種源碼塊,分析獲取每一種源碼塊的每一行代碼對應的ast信息;
步驟三:通過將獲取的語法結(jié)點信息組合成一個組合信息,使用該組合信息標識對應行,將標識一樣的相鄰代碼行組合成模塊;
步驟四:通過以模塊為單位對比分析兩個源碼塊的標識信息,根據(jù)模塊演化情況進行分類分析,使用預處理、二次處理方法處理各種演化情況,并將演化信息存入數(shù)據(jù)庫中,并轉(zhuǎn)換成html代碼。
本發(fā)明還可以包括:
1、步驟一中所述的將變化的源碼分為三種源碼塊具體包括:增加、刪除、改變,將變化的源碼分類成增加的源碼塊、刪除的源碼塊和改變的源碼塊存儲,以此為基礎(chǔ)進行進一步的分析處理。
2、步驟二中所述的分析獲取每一種源碼塊的每一行代碼對應的ast信息具體包括:
1)使用廣度優(yōu)先的搜索算法,根據(jù)行號逐個匹配antlr生成的抽象語法樹結(jié)點;
2)如果行號在結(jié)點的所屬的范圍內(nèi),逐個匹配此結(jié)點的子結(jié)點,直到找到完全匹配的行號結(jié)點;
3)使用語法分析器獲取當前行的語法元素以及上層語法元素,直到該源碼文件的頂層類或者函數(shù)、結(jié)構(gòu)體、枚舉類和共用體。
3、步驟三所述的組合信息的獲取,是使用標簽系統(tǒng)標識,它是類、函數(shù)、結(jié)構(gòu)體、枚舉類和共用體模塊的一個唯一標識,使用多個標識組合成一個標識代碼行的組合信息,標簽系統(tǒng)設計的方法是:
a)模塊的關(guān)鍵字是模塊的名字加上相應的屬性信息字符;
b)模塊的標識是使用多個字值對組合而成的,每兩個字值對之間都使用一個“@”字符來分隔;
c)模塊的層級標識之間使用“#”來分隔;
d)全局變量,預編譯處理和普通代碼行的關(guān)鍵字為stmsource,值為tempty。
4、步驟三中所述的組合成模塊,是根據(jù)標簽系統(tǒng)對diff劃分的源碼塊,進一步細分模塊,具體劃分模塊的步驟如下:
1)針對diff分析出的變化的源碼塊,根據(jù)行號獲取每一行代碼的標簽信息;
2)比對相鄰行代碼的標簽信息,根據(jù)比對情況分為兩種情況,一種是完整模塊,此模塊的開始行必須和它之前一行的標簽不一樣,并且模塊中間的每一行代碼的標簽是一樣的,另外此模塊的結(jié)束行必須和它之后的一行的標簽也不一樣,否則就不是一個完整模塊;
3)根據(jù)分析出的兩種情況,填充模塊信息數(shù)據(jù)結(jié)構(gòu),所述信息數(shù)據(jù)結(jié)構(gòu)包括模塊的開始行、結(jié)束行、模塊的類型、模塊的標簽信息。
5、步驟四中所述的根據(jù)模塊演化情況進行分類分析具體包括:進行類、函數(shù)信息的深入匹配分析,將兩個不同版本的對應信息和信息的固定格式進行對比,如果兩者都存在,而且有所改變,就是改變演化,如果舊版本沒有,存在增加演化,如果新版本沒有,存在刪除演化,如函數(shù)模塊的函數(shù)參數(shù)演化,函數(shù)模塊的返回值演化。
6、步驟四中所述的使用預處理、二次處理方法處理各種演化情況是一個遞歸過程,即每一次處理都需要預處理,所述預處理是一次正常對不同版本的同名源碼文件所有變化進行分析并將分析的結(jié)果進行存儲,如果分析到diff分析有誤,就進入二次處理,如果二次處理也再遇到diff分析錯誤,然后再進行預處理、二次處理,直到分析正確。
隨著軟件行業(yè)的蓬勃發(fā)展,軟件越來越復雜,軟件版本迭代次數(shù)越來越多,開發(fā)者接觸到的源代碼越來越多,同時這些軟件架構(gòu)也越來越復雜,軟件演化的規(guī)律也就愈加模糊,這就增加了開發(fā)者理解和維護軟件的難度。本發(fā)明提出了一種以diff為基礎(chǔ)的ast軟件版本演化對比分析方法,獲取類函數(shù)等模塊的演化信息,為軟件版本演化的理解提供依據(jù),并提高了軟件版本演化分析的準確率和效率。本發(fā)明的核心是面向軟件版本變化處的源碼,將變化處源碼的層次和關(guān)系更加精確、高效的體現(xiàn)出來,并遷移到軟件版本演化,致力于給用戶提供一個指導,減少軟件版本理解和維護的難度。
本發(fā)明的效果主要體現(xiàn)在:
現(xiàn)有的主流的軟件版本演化對比分析方法都是基于ast的,傳統(tǒng)的軟件演化分析大都是基于抽象語法樹的相似度匹配,并以此為基礎(chǔ)進行語法和語義信息的分析。但是相似就存在誤差,而且相似度的匹配需要與所有相似的對象匹配,效率不高。
現(xiàn)有的比較高效的軟件版本演化分析方法是,基于編輯距離(levenshteindistance,ld)算法的一種改進的基于ast的軟件演化分析方法。ld通常被用于輸入字符串的快速模糊匹配、英文輔助,寫作等領(lǐng)域,是一種經(jīng)典而廣為使用的方法。將ld算法的思想遷移到源碼的對比,基于ast的最短編輯距離算法分析分層結(jié)構(gòu)化代碼,假設分層結(jié)構(gòu)化代碼都是對稱的,類函數(shù)等模塊的語法結(jié)點都是一樣的,只是具體屬性有所變化?;诖朔椒ㄋ枷?,提出了一種改進的基于ast的軟件演化分析方法,提高了算法的效率和準確性,將算法的適用范圍拓寬了,不只限于分層結(jié)構(gòu)化代碼。
將ld算法從字符串的匹配應用到ast,其基本思想是一樣的。基于ast的最短編輯距離算法將問題分為三個步驟:
1)根據(jù)自定義規(guī)則,將ast轉(zhuǎn)換成需要的樹。
2)找到樹t1和t2的結(jié)點間的合適匹配集合。
3)根據(jù)匹配集合,找到最小將樹t1轉(zhuǎn)化為t2的編輯距離。
第一步需要將ast轉(zhuǎn)換成自己分析時所需的樹,那么源碼中所有的模塊信息都要根據(jù)樹的信息對應存儲,每一個結(jié)點的匹配都需要遍歷對應的存儲信息,工作量很大,在大規(guī)模軟件版本的演化分析中代價很高。也有的研究者將每一個結(jié)點映射成一個hash值,然后再進行匹配,雖然每一個結(jié)點的匹配過程會有一定的優(yōu)化,但是基于ast的最短編輯舉例算法還是必須將每一個結(jié)點映射存儲,分析時根據(jù)樹的編輯距離對每一個結(jié)點確定演化情況。自然存儲的信息越多,遍歷ast時對比分析的效率就越低。而本發(fā)明是根據(jù)變化的代碼行定位獲取ast信息,無需遍歷整個ast樹。
第二步是根據(jù)結(jié)點間的距離來匹配兩個結(jié)點,結(jié)點間的距離是通過結(jié)點的結(jié)構(gòu)和結(jié)點的類型分析,以及結(jié)合結(jié)點間的距離公式計算結(jié)點間的距離值,最后根據(jù)閾值確定結(jié)點是否匹配,其中距離公式和閾值是一個不穩(wěn)定因素,很有可能導致誤匹配和遺漏匹配的情況。
本發(fā)明是根據(jù)diff分析源碼的變化,使用語法分析器獲取的源碼ast信息修正diff分析的結(jié)果,從語義上分析和修正diff的錯誤分析,如將一個改變的代碼情況分析成增加和刪除。使用diff分析能準確分析出文本上的變化,使接下來的分析基礎(chǔ)非常高效準確。結(jié)合ast分析,設計并使用了標簽系統(tǒng),能高效的標識類函數(shù)等模塊信息,可以根據(jù)本發(fā)明使用的方法能高效的分析出類、函數(shù)、結(jié)構(gòu)體、共用體等模塊結(jié)構(gòu)的演化信息。
根據(jù)上述分析以及實驗表明,本發(fā)明和其他軟件版本演化對比分析方法相比,能提高獲取演化信息的準確率,并能提高軟件版本演化分析的效率。能有效分析出類函數(shù)等模塊結(jié)構(gòu)的演化信息,彌補了diff分析的不足,對git,cvs等源碼版本管理工具有更詳細的指導作用,對閱讀源碼、維護系統(tǒng)方面都有很好的指導作用。開發(fā)者可以借此方法來指導先期探索,加快理解工程,提升開發(fā)效率。進一步的發(fā)展,可以借此方法完成功能模塊的復用。
附圖說明
圖1為系統(tǒng)架構(gòu)圖diff源碼版本對比例子圖;
圖2為源碼版本v1和v2的diff分析正常格式結(jié)果圖;
圖3為add函數(shù)源碼圖;
圖4為源碼對應的ast圖;
圖5為語法樹節(jié)點對應的行號圖;
圖6為類函數(shù)等模塊標簽信息的獲取流程圖;
圖7為模塊信息表圖;
圖8為軟件版本演化差異分析流程圖;
圖9為配置文件configure.txt內(nèi)容圖;
圖10為測試環(huán)境結(jié)構(gòu)圖。
具體實施方式
下面舉例對本發(fā)明做更詳細的描述。
本發(fā)明的基于ast的軟件版本演化對比分析方法,主要包括如下幾個步驟:
步驟一:通過unix的diff命令對兩個軟件版本源碼進行比對分析,根據(jù)分析結(jié)果文件patch獲取代碼行的增加、刪除、改變的情況,將變化的源碼分為三種源碼塊。
步驟二:通過語法分析器獲取兩個軟件版本源碼的ast信息,針對第一步分析出的三種源碼塊,分析獲取每一種源碼塊的每一行代碼對應的ast信息。
步驟三:通過將獲取的語法結(jié)點信息組合成一個信息,使用該組合信息標識對應行,將標識一樣的相鄰代碼行組合成模塊。
步驟四:通過以模塊為單位對比分析兩個源碼塊的標識信息,根據(jù)模塊演化情況進行分類分析,使用預處理、二次處理等方法靈活處理各種演化情況,并將演化信息存入數(shù)據(jù)庫中,并轉(zhuǎn)換成html代碼;
步驟一將變化的源碼分為三種源碼塊,增加、刪除、改變,將變化的源碼分類成增加的源碼塊,刪除的源碼塊和改變的源碼塊存儲,以此為基礎(chǔ)進行進一步的分析處理,使處理流程更加合理、清晰。
步驟二獲取的每一行代碼對應的ast信息,本發(fā)明的獲取的代碼行對應的ast信息的方法,會將使用語法分析器獲取的源碼的ast的冗余信息去除,并無需遍歷整個抽象語法樹。具體的獲取步驟如下:
1)使用廣度優(yōu)先的搜索算法,根據(jù)行號逐個匹配antlr生成的抽象語法樹結(jié)點;
2)如果行號在結(jié)點的所屬的范圍內(nèi),會逐個匹配此結(jié)點的子結(jié)點,直到找到完全匹配的行號結(jié)點;
3)使用語法分析器獲取當前行的語法元素以及上層語法元素,直到該源碼文件的頂層類或者函數(shù)的類、函數(shù)、結(jié)構(gòu)體、枚舉類和共用體。
步驟三獲取標識代碼行的組合信息,是使用本發(fā)明設計的標簽系統(tǒng)標識,它是類、函數(shù)、結(jié)構(gòu)體、枚舉類和共用體模塊的一個唯一標識。使用多個標識組合成一個標識代碼行的組合信息,標簽系統(tǒng)是進一步細分模塊的標準,設計的原則是:
1)模塊的關(guān)鍵字是模塊的名字加上相應的屬性信息字符,如類的名字,使用“classname”關(guān)鍵字。
2)模塊的標識是使用多個字值對(關(guān)鍵字+“@”+值)組合而成的,每兩個字值對之間都使用一個“@”字符來分隔。
3)模塊的層級標識之間使用“#”來分隔,如類中的函數(shù),classname@math#functionname@add。
4)全局變量,預編譯處理和普通代碼行的關(guān)鍵字為stmsource,值為tempty
步驟三組合成的模塊,是根據(jù)標簽系統(tǒng)對diff劃分的源碼塊,進一步細分模塊,如類模塊,函數(shù)模塊。具體劃分模塊的步驟如下:
1)針對diff分析出的變化的源碼塊,根據(jù)行號獲取每一行代碼的標簽信息。
2)比對相鄰行代碼的標簽信息,根據(jù)比對情況分為兩種情況,一種是完整模塊,此模塊的開始行必須和它之前一行的標簽不一樣,并且模塊中間的每一行代碼的標簽是一樣的,另外此模塊的結(jié)束行必須和它之后的一行的標簽也不一樣,否則就不是一個完整模塊。
3)根據(jù)第二步分析出的兩種情況,填充模塊信息數(shù)據(jù)結(jié)構(gòu),如模塊的開始行,結(jié)束行,模塊的類型,模塊的標簽信息。
步驟四進行類、函數(shù)等信息的深入匹配分析,將兩個不同版本的對應的信息和信息的固定格式進行對比,如果兩者都存在,而且有所改變,就是改變演化,如果舊版本沒有,存在增加演化,如果新版本沒有,存在刪除演化,如函數(shù)模塊的函數(shù)參數(shù)演化,函數(shù)模塊的返回值演化。
步驟四所描述的預處理和二次處理是一個遞歸過程,就是每一次處理都需要預處理,預處理是一次正常對不同版本的同名源碼文件所有變化進行分析并將分析的結(jié)果進行存儲。如果分析到diff分析有誤,就會進入二次處理,二次處理也可能遇到diff分析錯誤,然后再進行預處理、二次處理,直到分析正確,預處理需要將分析到的數(shù)據(jù)分別存儲。
由于對許多文件對比軟件只能區(qū)分文件夾和文件變化的粗粒度信息,顯示哪幾行有增刪改,因此鑒于此種情況,本發(fā)明著眼于基于ast的軟件版本演化分析算法研究,主要研究的內(nèi)容是準確定位存在演化信息的ast結(jié)點,分析獲取類函數(shù)等模塊的屬性信息,并對演化情況進行分類,分析各種演化情況,提高演化分析的準確率和效率。本發(fā)明的研究由以下幾部分內(nèi)容組成:
1)如何準確定位存在演化信息的ast結(jié)點,本發(fā)明通過diff能準確定位變化的行號,根據(jù)行號能準確定位源碼ast存在演化的結(jié)點,但是diff分析出的結(jié)果存在錯誤,需要修正,如將一個改變的代碼情況分析成增加和刪除。
2)如何分析獲取類函數(shù)等模塊的屬性信息,本發(fā)明根據(jù)源碼的ast結(jié)點信息,分析每一類模塊的結(jié)點特點,并獲取屬性信息。
3)演化情況的分類及分析,本發(fā)明根據(jù)模塊的屬性信息,對演化情況分類,然后根據(jù)其特點設計相應的方法。
由于演化情況的多種多樣,具體的方法是由解決多個具體問題的具體方法組合實現(xiàn)的。整個方法流程主要涉及以下幾個部分:
1)diff分析結(jié)果劃分
diff是基于lcs算法實現(xiàn)的,用來對比分析新舊兩個版本文件的異同。操作方法是在系統(tǒng)終端界面中,輸入:$diff<舊版本文件><新版本文件>。diff的文本顯示不太友好,為了便于說明,舉例c++文件如附圖1所示。
diff有三種顯示格式:正常格式,上下文格式和合并格式,下面會介紹本發(fā)明使用的正常格式。
現(xiàn)在對v1和v2進行比較:$diffv1v2,此時,diff就會顯示正常格式的結(jié)果如附圖2所示。
每一個顯示部分都分為三部分:第一行是一個提示,用來說明變動位置,第一個"3",表示v1的第3行有變化;"c"(change)是一種改變模式的縮寫,另外還有兩個模式,分別為"a"(addition)代表增加和"d"(deletion)代表刪除;第二個"3",表示前面顯示的v1的第3行變成v2的第3行。第二行分成兩個部分,開頭的小于號,表示要從v1當中刪除第4行,"return0;"表示該行的內(nèi)容。第三行用來分割v1和v2,第四行,類似于第二行,前面的大于號表示v2增加了該行,后面的"return1;"表示該行的內(nèi)容。
對兩個源碼版本進行一次diff會生成一個patch文件,該patch文件包含了新舊源碼變化的對應的行號,而此處的行號,本發(fā)明會將其對應成一個源碼塊。根據(jù)diff分析的行號對應的增加、刪除、改變變化,總共有三種源碼塊,第一種是刪除的源碼塊,第二種是增加的源碼塊,第三種是改變的源碼塊。由于diff是針對文本行進行的lcs的處理,因此沒有語義信息,而且這種模塊的劃分,不會包含任何語義信息。另外對于一個模塊的位置變化,大多會分析成增加和刪除的改變。因此需要提出一種新的模塊劃分方法,這種方法需要體現(xiàn)語義信息,而且能進行更加高層次的演化分析,例如函數(shù)的參數(shù)變了,類的繼承關(guān)系變了。
2)標簽系統(tǒng)設計
標簽系統(tǒng)是類、函數(shù)、結(jié)構(gòu)體、枚舉類和共用體模塊的一個唯一標識,根據(jù)標簽系統(tǒng)針對diff劃分的源碼塊,進一步細分模塊,如類模塊,函數(shù)模塊。因此標簽系統(tǒng)是進一步細分模塊的標準,這個標簽系統(tǒng)設計的原則是:
(1)模塊的關(guān)鍵字是模塊的名字加上相應的屬性信息字符,如類的名字,使用“classname”關(guān)鍵字。
(2)模塊的標識是使用多個字值對(關(guān)鍵字+“@”+值)組合而成的,每兩個字值對之間都使用一個“@”字符來分隔。
(3)模塊的層級標識之間使用“#”來分隔,如類中的函數(shù),classname@math#functionname@add。
全局變量,預編譯處理和普通代碼行的關(guān)鍵字為stmsource,值為tempty
接下來就是關(guān)于各個模塊的各個關(guān)鍵字的介紹,具體如下:
(1)類的關(guān)鍵字
類模板:classtemplate@template,這里的template是為了湊字值對,沒有實際值。
類模板參數(shù):classtemplateparameter@(typenamet),模板參數(shù)是t。
類名:classname@math,一個名為math的類。
類繼承:classrelation@publiccircle,本類繼承自circle類。
(2)函數(shù)的關(guān)鍵字
函數(shù)模板:functiontemplate@template,這里的template是為了湊字值對,沒有實際值。
函數(shù)模板參數(shù):functiontemplateparameter@(typenamet),模板參數(shù)是t。
內(nèi)聯(lián)函數(shù):inlinefunction@inline,這里的inline是為了湊字值對,沒有實際值。
函數(shù)的返回值:functionreturn@int,這個函數(shù)的返回值是int。
函數(shù)名:functionname@add,一個名為add的函數(shù)。
函數(shù)參數(shù):functionparameters@(inta),此函數(shù)的參數(shù)是一個名為a的int類型。
其它的模塊,如結(jié)構(gòu)體、枚舉類和共用體的標識都比較簡單,這里就不一一贅述了。
3)基于ast的標簽系統(tǒng)信息的獲取
本發(fā)明是以diff分析為基礎(chǔ)的,diff分析出的變化是針對源碼的具體行的,而本發(fā)明是對每一行代碼進行類函數(shù)等模塊的標簽標識的,其關(guān)鍵字信息值的獲取是關(guān)鍵。本發(fā)明有別于其它的基于ast的演化分析是由于本發(fā)明是根據(jù)行號定位ast的關(guān)鍵字信息,無需遍歷整個抽象語法樹,這種方式增加了大型版本的軟件版本演化分析的能力,提高了效率和準確率。antlr分析出的抽象語法樹的每一個節(jié)點是有對應的行號信息的,如附圖3中源代碼對應的antlr生成的ast如附圖4所示,該圖中存在很多冗余信息,尤其是具體的變量和語句。將ast的冗余信息去除,處理過的語法樹的行號信息如附圖5所示。
本發(fā)明使用廣度優(yōu)先的搜索算法,根據(jù)行號逐個匹配antlr生成的抽象語法樹結(jié)點,如果行號在結(jié)點的所屬的范圍內(nèi),會逐個匹配此結(jié)點的子結(jié)點,直到找到完全匹配的行號結(jié)點。如本例中,如果要找行號2所對應的標簽信息,從根結(jié)點開始匹配,行號2的結(jié)點在根結(jié)點所屬范圍1~3之間,會繼續(xù)搜索根結(jié)點的子結(jié)點,從左邊第一個子結(jié)點開始,直到搜索到函數(shù)體的結(jié)點完全匹配。然后獲取函數(shù)體結(jié)點的父結(jié)點的第一個子結(jié)點信息,如函數(shù)名字,函數(shù)返回值類型,函數(shù)參數(shù)。最終將獲取的信息加上預先定義關(guān)鍵字的標簽信息,整個完整信息如下:
functionreturn@int@functionname@add@functionparameters@(inta,intb)
上述例子的語法樹結(jié)點信息是經(jīng)過處理的,實際的結(jié)點信息比較復雜,獲取ast信息的關(guān)鍵結(jié)點信息的具體流程如附圖6所示。
其中的結(jié)點名都是ast中的表達,它和實際模塊結(jié)點信息一一對應,本發(fā)明需要獲取類、函數(shù)、結(jié)構(gòu)體、枚舉類和共用體模塊的ast信息,然后才能使用標簽系統(tǒng)。本發(fā)明只舉例介紹類函數(shù)的詳細標簽信息獲取,其它模塊的標簽信息獲取,與此類似。附圖6中的流程圖首先會根據(jù)上述定位代碼行結(jié)點信息的方法獲取代碼行的結(jié)點信息,然后根據(jù)結(jié)點的名字信息和子結(jié)點信息的內(nèi)容獲取類函數(shù)模塊的具體信息,最后循著ast樹的父結(jié)點一直遍歷到根節(jié)點,將遍歷到的模塊信息組合成標簽信息。
4)基于標簽系統(tǒng)的分模塊處理
當能獲取每一行代碼的標簽之后,本發(fā)明就能將每一行代碼按標簽進行分類,分模塊。為此本發(fā)明設計了一個數(shù)據(jù)結(jié)構(gòu)來存儲模塊信息,具體模塊信息如附圖7所示,其中的名字標簽,就是語法標簽去掉了一些語法信息的結(jié)果,只有由每一個模塊的名字標簽組合在一起的字符串。其中type信息表示的是整個完整模塊的類型,如一個完整的函數(shù),而標號7則表示這塊的代碼只有模塊的一部分,例如只是函數(shù)其中的某一塊有演化,有可能是函數(shù)中增加了一行代碼。有了模塊信息之后就能分模塊處理,具體的步驟如下:
第一步,針對diff分析出的變化的源碼塊,根據(jù)行號獲取每一行代碼的標簽信息,這里有兩種標簽,一種是名字標簽,一種是語法標簽。
第二步,比對相鄰行代碼的兩種標簽信息,根據(jù)比對情況分為兩種情況,一種是完整模塊,就是附圖7中type為1-5的整個模塊的信息,此模塊的開始行必須和它之前一行的標簽不一樣,并且模塊中間的每一行代碼的標簽是一樣的,另外此模塊的結(jié)束行必須和它之后的一行的標簽也不一樣,否則就不是一個完整模塊,就是type為7的類型。
第三步,根據(jù)第二步分析出的兩種情況,填充模塊信息數(shù)據(jù)結(jié)構(gòu),如模塊的開始行,結(jié)束行,模塊的類型,模塊的名字標簽和語法標簽。
5)演化分類步驟
從類演化的數(shù)據(jù)結(jié)構(gòu)信息可以看出,模塊的演化分類是以類和函數(shù)等模塊的語法信息進行分類的,如類的修飾符演化,類的繼承關(guān)系演化,類的內(nèi)部一些模塊和非模塊演化次數(shù)的一些統(tǒng)計。根據(jù)diff分析的增加、刪除和改變,這里的增加、刪除和改變不是最終的,需要經(jīng)過分模塊化處理修正之后進一步分析,分模塊后的分類處理過程如下:
第一步,如果是一個模塊增加,則獲取軟件新版本關(guān)于此模塊的標簽的最底層的標簽,如classname@classsphere#functionname@add,這里最底層的標簽是函數(shù)add,只需獲取functionname的值,就說明存在一個函數(shù)增加的演化信息,并且說明類sphere中存在一個函數(shù)增加的演化信息,這兩個演化的統(tǒng)計方式是不一樣的。一個是實際演化的模塊統(tǒng)計演化關(guān)系,一個從層次歸屬體現(xiàn)演化關(guān)系。
第二步,如果是一個模塊刪除,同上,只不過是獲取軟件舊版本的信息,增加改成刪除。
第三步,如果是一個模塊的模塊體改變了,這里不論是增加,刪除,還是改變,都記錄成最底層模塊的一個內(nèi)容改變。如函數(shù)體中增加了一行,記錄此函數(shù)多了一次內(nèi)容改變。
第四步,如果是一個模塊屬性改變,這里的屬性指的是除了標識系統(tǒng)中的名字之外其它關(guān)于模塊的描述,如函數(shù)的返回值,參數(shù),是否內(nèi)聯(lián)都是此函數(shù)模塊的屬性。此處需要對比軟件新舊版本關(guān)于此模塊的最底層標簽,方法是使用一個關(guān)于底層模塊所有信息的完整關(guān)鍵字組成的標簽,如函數(shù)的如下:functiontemplate@functionparameter@inlinef-unction@functionreturn@functionname@functionparameters,假設從第一個標簽關(guān)鍵字functiontemplate開始,如果新舊軟件版本的標簽都有此關(guān)鍵字,就對比此關(guān)鍵字的值,如果是一樣的,說明此屬性是一樣的,如果不一樣,就記錄此屬性的改變信息,如果新舊標簽有一個沒有此關(guān)鍵字,就記錄一次屬性增加或刪除。
在軟件版本的演化過程中會分析兩個不同的軟件版本源碼,本發(fā)明將待分析的兩個軟件版本源碼分別標記為vi和v2,附圖8描述了軟件版本演化分析的整個過程。其中第一塊是針對同名同路徑的源碼文件進行diff分析,獲取patch文件,逐行處理patch文件,對每一種diff變化,進行分類處理,并分模塊處理類函數(shù)等模塊的相關(guān)演化,最終通過diff-ast算法的處理將分析的結(jié)果存儲到數(shù)據(jù)庫并轉(zhuǎn)換存儲成html頁面,既可以通過數(shù)據(jù)庫查看演化信息,也可以通過瀏覽器查看。第二塊是針對文件和文件夾的移動操作,使用md5的加密標簽處理,然后將移動的文件和文件夾的名字和路徑轉(zhuǎn)換成一張html的表,并將數(shù)據(jù)存入數(shù)據(jù)庫。
diff分析的結(jié)果顯示有三種方式,本發(fā)明使用正常格式的diff,會將分析的結(jié)果存儲到一個patch文件中。diff-ast算法會逐行分析patch文件,使用正在表達式“[0-9]+(,[0-9]+)?a[0-9]+(,[0-9]+)?.*”匹配增加變化,刪除變化和改變變化是相似的。接下來需要根據(jù)分析到的v1,v2變化的行號,通過開源語法分析器antlr獲取v1和v2的ast,基于ast去分析類函數(shù)等模塊的語法語義信息,構(gòu)建模塊的標簽信息,然后根據(jù)標簽進行分模塊處理,最終針對各種演化類型特點進行相應的算法設計和實現(xiàn),并將數(shù)據(jù)通過hibernate持久化技術(shù)存儲到mysql數(shù)據(jù)庫中,為了直觀的對軟件版本演化信息進行查看,也會將分析到的演化信息轉(zhuǎn)換成json格式的信息存儲到html頁面信息。
本實施既可以在eclipse軟件中進行,也可以在linux的終端環(huán)境中進行。在eclipse軟件中進行是使用工程的源碼進行分析,在linux的終端環(huán)境中進行是使用eclispe將工程源碼生成的diff-ast.jar包文件進行分析。這里只介紹linux的終端環(huán)境中進行的情況,在linux的終端環(huán)境中的當前目錄下需要一個配置文件configure.txt和軟件版本演化分析工具diff-ast.jar,配置文件configure.txt中的內(nèi)容如附圖9所示。
configure.txt中的第1到4行顯示軟件版本演化分析的新舊版本源碼的目錄和輸出文件patch和html的目錄,第5到8行顯示的數(shù)據(jù)庫連接的信息,本實施使用的是mysql數(shù)據(jù)庫,其中的信息包括數(shù)據(jù)庫的名字,數(shù)據(jù)庫的驅(qū)動,數(shù)據(jù)庫的用戶名和密碼,設計使用配置文件configure.txt提高了軟件版本演化分析工具的使用的靈活性。
在終端中運行命令$java-jardiff-ast.jarconfigure.txt會在相應的reportpath目錄下生成html文件,在html文件的根目錄下有一個index.html,可以使用瀏覽器打開,查看軟件版本演化的詳細信息,如增刪改的文件的數(shù)量以及源碼詳細的演化信息,具體的實施環(huán)境結(jié)構(gòu)如附圖10所示。