一種基于代碼克隆自動(dòng)檢測(cè)和及時(shí)提醒的軟件復(fù)用方法
【專利摘要】本發(fā)明公開(kāi)了一種基于代碼克隆自動(dòng)檢測(cè)和及時(shí)提醒的軟件復(fù)用方法,首先,利用詞法生成器工具生成Java詞法分析器。其次,后臺(tái)監(jiān)督器如果監(jiān)視到當(dāng)前編輯區(qū)代碼有修改,則將當(dāng)前編輯區(qū)代碼段和已開(kāi)發(fā)的代碼輸入Java詞法分析器,并按照轉(zhuǎn)換規(guī)則生成源代碼文件對(duì)應(yīng)的token值,并將這些token連接成一個(gè)Token序列,存儲(chǔ)在一維數(shù)組中,然后,采用倍增算法或DC3算法構(gòu)建后綴數(shù)組和名次數(shù)組以及生成最長(zhǎng)公共前綴數(shù)組。最后,從最長(zhǎng)公共前綴數(shù)組中過(guò)濾無(wú)意義的代碼片段,如果仍存在代碼克隆,則在集成開(kāi)發(fā)環(huán)境中提醒用戶復(fù)用或重構(gòu)這些代碼克隆。本發(fā)明方法實(shí)現(xiàn)了用戶邊開(kāi)發(fā),后臺(tái)監(jiān)督器邊檢測(cè)源代碼的功能。
【專利說(shuō)明】一種基于代碼克隆自動(dòng)檢測(cè)和及時(shí)提醒的軟件復(fù)用方法
【技術(shù)領(lǐng)域】
[0001]本發(fā)明屬于軟件維護(hù)與軟件再工程領(lǐng)域,涉及一種自動(dòng)檢測(cè)和及時(shí)提醒的軟件復(fù)用方法。
【背景技術(shù)】
[0002]軟件系統(tǒng)中軟件克隆代碼的檢測(cè)是軟件工程中研究的熱點(diǎn)之一,它在軟件維護(hù),架構(gòu),進(jìn)化,專利和剽竊等領(lǐng)域有著廣泛的應(yīng)用。為了提高開(kāi)發(fā)效率,開(kāi)發(fā)者經(jīng)常對(duì)軟件系統(tǒng)的源代碼進(jìn)行復(fù)制-粘貼-修改活動(dòng),這種重用機(jī)制通常會(huì)導(dǎo)致在源代碼庫(kù)中出現(xiàn)很多相同或相似的代碼段,這類代碼段被稱為克隆代碼。另外,開(kāi)發(fā)者腦海中對(duì)于相似功能實(shí)現(xiàn)方法的固化也使得他們常常會(huì)在不同的地方寫(xiě)出相似的代碼段。此外,程序員使用特定的設(shè)計(jì)模式框架及API等來(lái)完成相似的程序任務(wù),也會(huì)產(chǎn)生一些無(wú)意的克隆代碼。研究表明,一個(gè)軟件系統(tǒng)可能會(huì)有10%到20%的克隆代碼。代碼克隆是一種典型的“壞味道”,它增加了軟件系統(tǒng)代碼的長(zhǎng)度,它在很多情況下降低了軟件的可理解性和可維護(hù)性,增加了軟件維護(hù)的成本。如果許多克隆的代碼分散在軟件系統(tǒng)中的不同地方,那么修改一處代碼就要求其他克隆的代碼也要被修改,而如果文檔得不到及時(shí)的更新,那么想要保持源代碼的一致性就十分困難,修改了一部分克隆代碼而忽略了其他的克隆代碼,這樣引入的錯(cuò)誤很可能在運(yùn)行時(shí)才會(huì)呈現(xiàn)出來(lái)。由此可見(jiàn),代碼克隆是對(duì)程序結(jié)構(gòu)的一種破壞,減少代碼克隆就能在一定程度上降低軟件系統(tǒng)維護(hù)的負(fù)擔(dān),降低錯(cuò)誤出現(xiàn)的概率。因此,我們需要對(duì)軟件代碼進(jìn)行克隆檢測(cè),以決定對(duì)其實(shí)施必要的重構(gòu)。
[0003]現(xiàn)階段的代碼克隆檢測(cè)工具,很多是半自動(dòng)的或者開(kāi)發(fā)者驅(qū)動(dòng)的,而且與集成開(kāi)發(fā)環(huán)境是分離的,這種分離使得開(kāi)發(fā)者實(shí)施克隆代碼檢測(cè)時(shí)必須重新手工啟用第三方軟件,降低了操作的便利性。同時(shí),這種分離也導(dǎo)致克隆代碼產(chǎn)生時(shí)沒(méi)能及時(shí)地反饋給開(kāi)發(fā)者,致使可能錯(cuò)失良好的克隆代碼合并時(shí)機(jī)。如果將調(diào)用克隆檢測(cè)工具的時(shí)機(jī)推遲到軟件發(fā)布階段,此時(shí)代碼克隆的合并將可能會(huì)付出更大的代價(jià)。
[0004]此外,當(dāng)前的軟件克隆檢測(cè)框架大部分是采用先進(jìn)的搜索或比對(duì)技術(shù)盡力查找并反饋軟件中所有的克隆代碼。這種檢測(cè)的難點(diǎn)是用戶事先并不知道哪些代碼段可能存在重復(fù)。因此,檢測(cè)工具需要將每一個(gè)代碼段與其它所有的代碼段進(jìn)行相似性比較,這種檢測(cè)的時(shí)空復(fù)雜度往往都非常高。為了減少檢測(cè)結(jié)果的誤報(bào)和漏報(bào),或增加檢測(cè)的克隆類型,學(xué)者們相繼提出了許多先進(jìn)的克隆檢測(cè)方法與技術(shù)。然而,這些方法和技術(shù)中存在下列問(wèn)題:對(duì)于中小規(guī)模的軟件,當(dāng)前流行的檢測(cè)工具可以很好地滿足克隆檢測(cè)要求,但在檢測(cè)大規(guī)模軟件時(shí)它們耗費(fèi)了大量的內(nèi)存與時(shí)間,很難做到大規(guī)模檢測(cè)的實(shí)時(shí)性;其次,當(dāng)前的檢測(cè)工具與集成開(kāi)發(fā)環(huán)境是分離的,且大多數(shù)需要手動(dòng)調(diào)用,難以支持自動(dòng)實(shí)時(shí)檢測(cè),致使克隆代碼產(chǎn)生后,未能得到用戶及時(shí)關(guān)注。再次,當(dāng)前的檢測(cè)方法總是試圖搜遍整個(gè)代碼庫(kù),然后將所有的克隆對(duì)或克隆群以某種可視化的方式呈現(xiàn)給開(kāi)發(fā)者,致使開(kāi)發(fā)者花費(fèi)很大精力定位自己真正感興趣的克隆,增加了用戶復(fù)用代碼或重構(gòu)的負(fù)擔(dān)。
【發(fā)明內(nèi)容】
[0005]技術(shù)問(wèn)題:本發(fā)明提供一種基于代碼克隆自動(dòng)檢測(cè)和及時(shí)提醒的軟件復(fù)用方法。該方法提高了軟件復(fù)用效率,實(shí)現(xiàn)了克隆代碼的自動(dòng)檢測(cè)和及時(shí)提醒,降低了軟件維護(hù)的成本。
[0006]技術(shù)方案:本發(fā)明的基于代碼克隆自動(dòng)檢測(cè)和及時(shí)提醒的軟件復(fù)用方法,后臺(tái)監(jiān)督器持續(xù)監(jiān)視當(dāng)前編輯區(qū)代碼是否有修改,如果有則按照以下步驟進(jìn)行軟件復(fù)用檢測(cè):
[0007]步驟I)利用詞法分析器的生成工具生成基于token的Java詞法分析程序;
[0008]步驟2)將源代碼標(biāo)準(zhǔn)化:將項(xiàng)目中已經(jīng)開(kāi)發(fā)完的代碼和當(dāng)前編輯區(qū)域的代碼段分別輸入所述步驟I)中生成的Java詞法分析程序,生成每個(gè)源文件對(duì)應(yīng)的token值,即刪除空格符、注釋和包,同時(shí)根據(jù)轉(zhuǎn)換規(guī)則將源代碼轉(zhuǎn)換為T(mén)okens ;
[0009]步驟3)將所述步驟2)中得到的各個(gè)Tokens連接成一個(gè)Token序列,并存儲(chǔ)在一維數(shù)組TokenArray []中,然后采用倍增算法或DC3算法構(gòu)建一維數(shù)組TokenArray []所對(duì)應(yīng)的后綴數(shù)組SuffixArray [],最后遍歷所述后綴數(shù)組SuffixArray [],生成名次數(shù)組RankArray[];
[0010]步驟4)利用所述后綴數(shù)組SuffixArray []和名次數(shù)組RankArray [],生成用于查找與當(dāng)前編輯區(qū)代碼片段相似的語(yǔ)句片段的最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray [],所述最長(zhǎng)公共前綴數(shù)組 LongestCommonPrefixArray []含有與當(dāng)前編輯區(qū)代碼片段相似的代碼克隆群;
[0011]步驟5)將所述最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray []中的代碼克隆群中無(wú)意義的代碼片段剔除,然后檢測(cè)所述步驟5)中剔除無(wú)意義的代碼片段后的代碼克隆群,如果存在代碼克隆,則在集成開(kāi)發(fā)環(huán)境中提醒用戶復(fù)用、合并或重構(gòu)這些代碼克隆。
[0012]本發(fā)明方法的步驟2)中的轉(zhuǎn)換規(guī)則為:
[0013]規(guī)則1:將源代碼中的基本數(shù)據(jù)類型、包裝數(shù)據(jù)類型和泛型均用字母T替換;
[0014]規(guī)則2:將源代碼中的關(guān)鍵字for、while、if、else、case作如下轉(zhuǎn)換,for — F,while — W,if — I,else —,case — C ;
[0015]規(guī)則3:將類名,類成員變量名,類成員方法名,類的實(shí)例名均替換為字符N,數(shù)組名替換為字符R;
[0016]規(guī)則4:將源代碼中的整數(shù),浮點(diǎn)數(shù),字符常量用O替換,字符串常量用s替換;
[0017]規(guī)則5:去掉包名,將包名+類名替換成類名;
[0018]規(guī)則6:補(bǔ)全調(diào)用者,具體為:對(duì)于一個(gè)對(duì)象調(diào)用自己的方法,且該方法的前面沒(méi)有對(duì)象名或類名時(shí),需將對(duì)象名或類名添加到方法名的前面;
[0019]規(guī)則7:將初始化列表中的內(nèi)容替換為空;
[0020]規(guī)則8:去掉注釋、包和空格。
[0021]本發(fā)明方法的一種優(yōu)選方案中,步驟4)中,最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray []中的代碼克隆群為對(duì)應(yīng)的一維數(shù)組TokenArray []中token個(gè)數(shù)大于最小有效token閾值的代碼克隆群。
[0022]本發(fā)明基于后綴數(shù)組的算法實(shí)現(xiàn)了代碼克隆的實(shí)時(shí)檢測(cè)和及時(shí)提醒,這種技術(shù)能夠在項(xiàng)目的內(nèi)部實(shí)現(xiàn)語(yǔ)句塊層面細(xì)粒度的復(fù)用。
[0023]有益效果:與現(xiàn)有技術(shù)相比,本發(fā)明具有如下優(yōu)點(diǎn):
[0024]現(xiàn)有的代碼克隆檢測(cè)大多利用度量技術(shù)、抽象語(yǔ)法樹(shù)、程序依賴圖以及數(shù)據(jù)挖掘方法。這些方法有的檢測(cè)的粒度很細(xì),但算法時(shí)空效率較高,難以達(dá)到大規(guī)模和實(shí)時(shí)檢測(cè)要求。其次,當(dāng)前的代碼克隆檢測(cè)工具大多數(shù)獨(dú)立于開(kāi)發(fā)環(huán)境,開(kāi)發(fā)者調(diào)用花銷時(shí)間太大,因此,往往帶來(lái)了檢測(cè)的滯后性,導(dǎo)致開(kāi)發(fā)者錯(cuò)過(guò)代碼復(fù)用的機(jī)會(huì)。另外,很多工具提供給開(kāi)發(fā)者的是系統(tǒng)中全部的代碼克隆,而開(kāi)發(fā)者往往關(guān)心的只是跟當(dāng)前編輯代碼有關(guān)的克隆代碼塊,這給開(kāi)發(fā)者選擇可復(fù)用代碼塊帶來(lái)的困難。為此,本發(fā)明方法針對(duì)以上提及的不足進(jìn)行如下改進(jìn):
[0025](I)本方法采用后綴數(shù)組表示token序列,這種數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)簡(jiǎn)單,而且在處理重復(fù)子串的問(wèn)題上比后綴樹(shù)具有更優(yōu)的時(shí)空復(fù)雜度。從后綴數(shù)組的構(gòu)造至查找出克隆代碼群所用的總時(shí)間復(fù)雜度為0(n),而η為轉(zhuǎn)換后的token序列長(zhǎng)度。這使得本發(fā)明方法能夠?qū)崿F(xiàn)大規(guī)模實(shí)時(shí)檢測(cè)要求。
[0026](2)本發(fā)明采用的檢測(cè)方法將作為Eclipse的插件提供為用戶使用,實(shí)現(xiàn)了用戶邊編寫(xiě)代碼,邊自動(dòng)檢測(cè)的功能,克服了用戶被動(dòng)地調(diào)用或在版本發(fā)布時(shí)才想到調(diào)用代碼克隆工具的局限。而傳統(tǒng)的檢測(cè)工具大多脫離集成開(kāi)發(fā)環(huán)境,即使以插件形式提供給用戶使用,仍然需要開(kāi)發(fā)者手工調(diào)用工具,但本發(fā)明的方法克服這一弊端,實(shí)現(xiàn)了在軟件開(kāi)發(fā)的早期階段提醒用戶實(shí)施代碼復(fù)用或重構(gòu),從而避免了引入新的代碼克隆,有效地提高了軟件的可維護(hù)性。
[0027](3)該方法過(guò)濾了開(kāi)發(fā)者不感興趣的代碼克隆,只呈現(xiàn)與當(dāng)前正在開(kāi)發(fā)的代碼塊相關(guān)的代碼克隆,如果將系統(tǒng)中所有的代碼克隆全部提供給開(kāi)發(fā)者,隨著系統(tǒng)規(guī)模的增大,將會(huì)導(dǎo)致大量暫時(shí)開(kāi)發(fā)者并不急于復(fù)用的代碼克隆,這些代碼克隆淹沒(méi)的開(kāi)發(fā)者真正感興趣的復(fù)用塊,增加了開(kāi)發(fā)者定位代碼克隆的開(kāi)銷,而本發(fā)明方法克服了這一弊端,因此,該方法提高了復(fù)用的效率和準(zhǔn)確率。
[0028](4)傳統(tǒng)的方法往往局限于檢測(cè)方法級(jí)上的代碼克隆,這種復(fù)用粒度較粗,在實(shí)際的開(kāi)發(fā)中,方法體往往會(huì)比較大,開(kāi)發(fā)者真正想復(fù)用的只是方法中某一段代碼塊。而本方法檢測(cè)的粒度在代碼塊層面,從而在項(xiàng)目的內(nèi)部實(shí)現(xiàn)了語(yǔ)句塊層面細(xì)粒度的復(fù)用,提高了開(kāi)發(fā)的效率。
【專利附圖】
【附圖說(shuō)明】
[0029]圖1是基于后綴數(shù)組的實(shí)時(shí)克隆搜索和復(fù)用提醒的執(zhí)行流程示意圖。
【具體實(shí)施方式】
[0030]下面將結(jié)合實(shí)施例和說(shuō)明書(shū)附圖對(duì)本發(fā)明做進(jìn)一步詳細(xì)說(shuō)明說(shuō)明。
[0031]在介紹具體技術(shù)方案之前,先闡釋幾個(gè)與本發(fā)明相關(guān)的的概念。
[0032](I)代碼片段
[0033]代碼片段(Code Fragment)是任意一個(gè)代碼行序列(可能包含注釋,也可能不包含注釋)。它可以是任意粒度的,例如,代碼片段可以是一個(gè)函數(shù)的定義,一個(gè)begin-end語(yǔ)句塊或者一個(gè)語(yǔ)句序列。一個(gè)代碼片段可通過(guò)它所在的文件名、源代碼中的起始行號(hào)和結(jié)束行號(hào)來(lái)標(biāo)識(shí),它可以通過(guò)一個(gè)三元組表示:文件名,起始代碼行行號(hào),結(jié)束代碼行行號(hào)。
[0034](2)代碼克隆
[0035]代碼片段CF2是另一個(gè)代碼片段CFl的一個(gè)克隆,是指根據(jù)一些給定的相似性度量函數(shù)定義它們之間是相似的,也就是說(shuō),f(CFl) = f(CF2),f表示相似度函數(shù)。兩個(gè)相似的代碼片段構(gòu)成了一個(gè)克隆對(duì),多個(gè)相似的代碼片段構(gòu)成了一個(gè)克隆類或克隆組。
[0036](3)代碼克隆類型
[0037]類型一(Type-1):除空格、布局和注釋不同之外,其余部分都相同的代碼片段。
[0038]類型二(Type-2):除標(biāo)識(shí)符、字面量、類型、空格、布局和注釋外,語(yǔ)法結(jié)構(gòu)相同的代碼片段。
[0039]類型三(Type-3):除標(biāo)識(shí)符、字面量、類型、空格、布局和注釋外,進(jìn)一步對(duì)克隆代碼段進(jìn)行改動(dòng),例如修改、增加或者刪除語(yǔ)句。
[0040]類型四:兩個(gè)或多個(gè)代碼片段執(zhí)行相同的計(jì)算,但是語(yǔ)法結(jié)構(gòu)的實(shí)現(xiàn)方式不同。
[0041]以上克隆類型定義中,Type-1克隆的定義最為精確,Type-2克隆的定義不夠精確,而Type-3與Type-4克隆的界定存在更高的模糊性。同時(shí),四類克隆代碼的定義都是基于代碼片段的概念。所以從代碼片段的粒度來(lái)看,克隆代碼有以下五種類型:如果兩個(gè)文件內(nèi)的源代碼相同或相似,則它們被稱為文件克??;在面向?qū)ο笳Z(yǔ)言的代碼中,如果兩個(gè)類相同或相似,則被稱為類克??;當(dāng)兩個(gè)函數(shù)或方法中的代碼非常相似時(shí),則這兩個(gè)函數(shù)被稱為函數(shù)克??;當(dāng)兩個(gè)代碼塊(由開(kāi)始和結(jié)束的花括號(hào)或縮進(jìn)等標(biāo)識(shí)的代碼段)非常相似時(shí),則它們被稱為塊克??;當(dāng)兩組語(yǔ)句代碼(語(yǔ)句間連續(xù))非常相似,則這兩組語(yǔ)句被稱為語(yǔ)句克隆。因此在克隆代碼研究中,時(shí)常將代碼相似度與檢測(cè)粒度結(jié)合起來(lái)界定克隆代碼。本發(fā)明主要關(guān)注代碼塊層面的克隆。
[0042](4)源代碼的中間表示
[0043]目前,國(guó)內(nèi)外學(xué)者已提出許多克隆檢測(cè)算法與技術(shù),這些技術(shù)之間的差異點(diǎn)在于代碼的中間表示,克隆匹配算法以及克隆檢測(cè)的粒度。根據(jù)源代碼的中間表示,這些方法可大致地分成六類:基于文本、基于詞法(Token)、基于語(yǔ)法(Syntax)、基于語(yǔ)義、基于Metrics、基于低級(jí)語(yǔ)言。本發(fā)明中的源代碼中間表示是基于詞法的。
[0044]本發(fā)明的基于代碼克隆自動(dòng)檢測(cè)和及時(shí)提醒的軟件復(fù)用方法,其內(nèi)部采用的檢測(cè)方法是基于token數(shù)組的,且能檢測(cè)出Type-2類型的代碼克隆,具體包括以下步驟:
[0045]步驟I)利用詞法分析器的生成工具生成基于token的Java詞法分析程序;本發(fā)明所采用的詞法分析器生成工具是Jflex,此工具是開(kāi)源的;
[0046]步驟2)將源代碼標(biāo)準(zhǔn)化:將項(xiàng)目中已經(jīng)開(kāi)發(fā)完的代碼和當(dāng)前編輯區(qū)域的代碼段分別輸入所述步驟I)中生成的Java詞法分析程序,生成每個(gè)源文件對(duì)應(yīng)的token值,即刪除空格符、注釋和包,同時(shí)根據(jù)轉(zhuǎn)換規(guī)則將源代碼轉(zhuǎn)換為T(mén)okens,其中轉(zhuǎn)換規(guī)則如下:
[0047]規(guī)則1:將源代碼中的基本數(shù)據(jù)類型、包裝數(shù)據(jù)類型和泛型均用字母T替換;為方便理解,這里的字母T取自Type的首字母。同時(shí)為下文敘述方便,式子“X — y”表示X被替換為 t匕如,int x — T x> Integer inte — T inte 以及 ArrayList〈Dog>arr — ArrayList〈T>arr,其中Dog是類名;
[0048]規(guī)則2:將源代碼中關(guān)鍵字for、while、if、else和case作如下轉(zhuǎn)換,for — F、while — W、if — 1、else — E、case — C ;
[0049]規(guī)則3:將類名,類成員變量名,類成員方法名,類的實(shí)例名均替換為字符N,數(shù)組名替換為字符R;
[0050]規(guī)則4:將源代碼中的整數(shù),浮點(diǎn)數(shù),字符常均替換為0,字符串常量用s替換;
[0051]規(guī)則5:去掉包名,將包名+類名替換成類名;例如,包名cn.seu.cloneTest加類名 PatternTest 的字符串 package cn.seu.cloneTest PatternTest 將被替換為PatternTest,降低轉(zhuǎn)換后token數(shù)組的存儲(chǔ)空間;
[0052]規(guī)則6:補(bǔ)全調(diào)用者,具體為:對(duì)于一個(gè)對(duì)象調(diào)用自己的方法,且該方法的前面沒(méi)有對(duì)象名或類名時(shí),需將對(duì)象名或類名添加到方法名的前面。如類Dog中方法getColor O,則將getColorO替換為this.getColor O ,這里的this即為方法getColor O的調(diào)用對(duì)象,而類Math中cos O方法則需要補(bǔ)全為Math, cos O ;
[0053]規(guī)則7:將初始化列表中的內(nèi)容替換為空,如將“={InitList} ”替換為“={} ”其中InitList是名字、數(shù)字、字符串、操作符、,(),{}的序列組合;
[0054]規(guī)則8:去掉注釋、包和空格;
[0055]設(shè)計(jì)轉(zhuǎn)換規(guī)則的目的是消除代碼中結(jié)構(gòu)的差異,也是為了能檢測(cè)出Type-2類型的代碼克隆,規(guī)則I至規(guī)則8的設(shè)計(jì)只適合java語(yǔ)言機(jī)制。
[0056]步驟3)將所述步驟2)中得到的各個(gè)Tokens連接成一個(gè)Token序列,并存儲(chǔ)在一維數(shù)組TokenArray []中,然后采用倍增算法或DC3算法構(gòu)建一維數(shù)組TokenArray []所對(duì)應(yīng)的后綴數(shù)組SuffixArray [],最后遍歷所述后綴數(shù)組SuffixArray [],生成名次數(shù)組RankArray [];假設(shè)TokenArray的長(zhǎng)度是N,則DC3算法和生成名次數(shù)組的時(shí)空復(fù)雜度均是O(N);
[0057]步驟3)中的 DC3 算法(Difference Cover mod3)是 J.KSrkkSineri和 P.Sanders在 2003 年發(fā)表的論文"Simple Linear Work Suffix Array Construct1n"中描述的線性時(shí)間內(nèi)構(gòu)造后綴數(shù)組的算法。DC3算法的思想類似于找中位數(shù)的median of medians算法。相對(duì)前綴倍增(Prefix Doubling)算法而言,它的漸進(jìn)時(shí)間復(fù)雜度比較小,但常數(shù)項(xiàng)比較大。
[0058]本發(fā)明方法的另一種實(shí)施例中,步驟3)中采用現(xiàn)有成熟的倍增算法構(gòu)建一維數(shù)組TokenArray []所對(duì)應(yīng)的后綴數(shù)組SuffixArray []。
[0059]步驟4)利用所述后綴數(shù)組SuffixArray []和名次數(shù)組RankArray [],生成用于查找與當(dāng)前編輯區(qū)代碼片段相似的語(yǔ)句片段的最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray [],所述的最長(zhǎng)公共前綴數(shù)組 LongestCommonPrefixArray []含有與當(dāng)前編輯區(qū)代碼片段相似的代碼克隆群。獲取與當(dāng)前編輯區(qū)代碼片段相似的克隆群時(shí),分如下兩步:
[0060](I)計(jì)算兩個(gè)后綴的最長(zhǎng)公共前綴需要利用GetHeight算法生成Height數(shù)組,該數(shù)組中的信息可在線性時(shí)間內(nèi)計(jì)算出最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray ;
[0061](2)通過(guò)步驟2)獲得當(dāng)前編輯區(qū)代碼片段標(biāo)準(zhǔn)化后的位置,假設(shè)其位置為SuffixArray [k] = j,則與當(dāng)前編輯區(qū)代碼段相似的代碼克隆為T(mén)okenArray [j]的Height [k]個(gè)前綴字符。
[0062]步驟5)將所述最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray 口中的代碼克隆群中無(wú)意義的代碼片段剔除,然后檢測(cè)所述步驟5)中剔除無(wú)意義的代碼片段后的代碼克隆群,如果存在代碼克隆,則在集成開(kāi)發(fā)環(huán)境中提醒用戶復(fù)用或重構(gòu)這些代碼克隆。剔除無(wú)意義的代碼克隆含有以下情形:
[0063](I)當(dāng)克隆代碼塊小于最小有效token閾值時(shí),將剔除此克隆代碼塊;這里的最小token閾值可以由用戶根據(jù)復(fù)用代碼行的多少進(jìn)行設(shè)定。最小token閾值也可以通過(guò)啟發(fā)式的方法確定,即通過(guò)統(tǒng)計(jì)用戶復(fù)用代碼行的平均值得出最小token閾值。通過(guò)實(shí)驗(yàn),我們得出最小有效token閾值為10時(shí),檢測(cè)效果較好。
[0064](2)當(dāng)克隆代碼塊橫跨兩個(gè)方法時(shí),將剔除此克隆代碼塊;
[0065](3)當(dāng)克隆代碼塊中只是數(shù)組或?qū)ο蟮某跏蓟瘯r(shí),將剔除此克隆代碼塊,因?yàn)檫@些克隆代碼塊通常復(fù)用意義很小;
[0066]實(shí)施例:
[0067]1.下面將通過(guò)具體的代碼說(shuō)明整個(gè)操作的流程。
[0068]OL packagc cn.scu.dcmeTest;
02.public class PatternTest {
03.public sialic void showNumber( ) |
04.Siring a[] ^ new SlringU { "123456' lfyou arc a boy.M};
05.javaJang.Slring paltern^ncw Slring(fiarcif);
06.//codc similarity lest
07,ini sum=0;
08,for(int i = 0; i < a.lcngth; ++"
09,if (patieim*matelies(a[i]))
10,sum += Parseiipar驟Nuinber(pattem);
11.System.0ut4)rinlto("mm: H + sum);
12.}
!3, public sialic ini parseSlring(Siring s){
!4.return I;
15, }
16* sialic void prinlPaltcm(Slring[] s) j
TL Siring exp = new java,lang.Slring(_’[0-9,]+:,》;
18.long I = 0;
19.for(int i = 0; i < s,length;十十i)|
20.1f (cxp.matchcs(s[i])) {
21.1 += parseString(cxp); //defauli invocat1n
22.}
23.}
24.System.οαΙ*ρ--Π?Ιη(,!1 = + I);
)
26.}
[0069]步驟I),利用詞法分析器的生成工具生成基于token的Java詞法分析程序;本發(fā)明所采用的詞法分析器生成工具是Jflex ;
[0070]步驟2),將源代碼標(biāo)準(zhǔn)化:將項(xiàng)目中已經(jīng)開(kāi)發(fā)完的代碼和當(dāng)前編輯區(qū)的代碼段分別輸入所述步驟I)中生成的Java詞法分析程序,生成每個(gè)源文件對(duì)應(yīng)的token值,在生成的過(guò)程中將代碼中包,注釋,空格等無(wú)關(guān)信息過(guò)濾。其中,第一行代碼的cn.seu.cloneTest即為包名。將源代碼進(jìn)行標(biāo)準(zhǔn)化后的中間代碼如下:
[0071]classN {
[0072]TNO {
[0073]TN [] = newT[] {};
[0074]TN = newT (O);
[0075]TN = O ;
[0076]for (TN = O ;N<N.N ;++N)
[0077]if (N.N(N[N]))
[0078]N+ = N.N (N);
[0079]N.N (s+N);
[0080]}
[0081]TN(TN) {
[0082]RO ;
[0083]}
[0084]TN(T[]N) {
[0085]TN = newT (0);
[0086]TN = 0 ;
[0087]for (TN = 0 ;N<N.N ;++N)
[0088]if (N.N(N[N]))
[0089]N+ = N.N (N);
[0090]N.N (s+N);
[0091]}
[0092]}
[0093]步驟3),我們得到token串序列的數(shù)組TokenArray,其內(nèi)容如下:
[0094]classN{TN() {TN[] = newT[] {} ;TN = newT(0) ;TN = 0 ;for (TN = 0 ;N<N.N ;++N)if (N.N(N[N]))N+ = N.N(N) ;N.N(s+N) ;} TN(TN) {R0 ;}TN(T[]N) {TN = newT (0) ;TN = 0 ;for(TN = 0 ;N<N.N ;++N)if(N.N(N[N]))N+ = N.N(N) ;N.N(s+N) ;}}
[0095]其中TokenArray數(shù)組的長(zhǎng)度為183,它是計(jì)算最長(zhǎng)公共前綴數(shù)組和Height數(shù)組
[0096]的基礎(chǔ)。采用倍增或DC3算法可得到后綴數(shù)組SuffixArray □,然后對(duì)其進(jìn)行一遍掃描,
[0097]生成名次數(shù)組RankArray[],為節(jié)省篇幅,這兩個(gè)數(shù)組的內(nèi)容均節(jié)選前5個(gè)元素,見(jiàn)
[0098]表1。
[0099]
【權(quán)利要求】
1.一種基于代碼克隆自動(dòng)檢測(cè)和及時(shí)提醒的的軟件復(fù)用方法,其特征在于,該方法中,后臺(tái)監(jiān)督器持續(xù)監(jiān)視當(dāng)前編輯區(qū)代碼是否有修改,如果有則按照以下步驟進(jìn)行軟件復(fù)用檢測(cè): 步驟I)利用詞法分析器的生成工具生成基于token的Java詞法分析程序; 步驟2)將源代碼標(biāo)準(zhǔn)化:將項(xiàng)目中已經(jīng)開(kāi)發(fā)完的代碼和當(dāng)前編輯區(qū)域的代碼段分別輸入所述步驟I)中生成的Java詞法分析程序,生成每個(gè)源文件對(duì)應(yīng)的token值,即刪除空格符、注釋和包,同時(shí)根據(jù)轉(zhuǎn)換規(guī)則將源代碼轉(zhuǎn)換為T(mén)okens ; 步驟3)將所述步驟2)中得到的各個(gè)Tokens連接成一個(gè)Token序列,并存儲(chǔ)在一維數(shù)組TokenArray []中,然后采用倍增算法或DC3算法構(gòu)建一維數(shù)組TokenArray[]所對(duì)應(yīng)的后綴數(shù)組SuffixArray □,最后遍歷所述后綴數(shù)組SuffixArray [],生成名次數(shù)組RankArray[]; 步驟4)利用所述后綴數(shù)組SuffixArray []和名次數(shù)組RankArray [],生成用于查找與當(dāng)前編輯區(qū)代碼片段相似的語(yǔ)句片段的最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray □,所述最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray []含有與當(dāng)前編輯區(qū)代碼片段相似的代碼克隆群; 步驟5)將所述最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray[]中的代碼克隆群中無(wú)意義的代碼片段剔除,然后檢測(cè)所述步驟5)中剔除無(wú)意義的代碼片段后的代碼克隆群,如果存在代碼克隆,則在集成開(kāi)發(fā)環(huán)境中提醒用戶復(fù)用、合并或重構(gòu)這些代碼克隆。
2.根據(jù)權(quán)利要求1所述的基于代碼克隆自動(dòng)檢測(cè)和及時(shí)提醒的軟件復(fù)用方法,其特征在于,所述步驟2)中的轉(zhuǎn)換規(guī)則為: 規(guī)則1:將源代碼中的基本數(shù)據(jù)類型、包裝數(shù)據(jù)類型和泛型均用字母T替換; 規(guī)則2:將源代碼中的關(guān)鍵字for、while、if、else、case作如下轉(zhuǎn)換,for — F,while — W, if — I, else —, case — C ; 規(guī)則3:將類名,類成員變量名,類成員方法名,類的實(shí)例名均替換為字符N,數(shù)組名替換為字符R ; 規(guī)則4:將源代碼中的整數(shù),浮點(diǎn)數(shù),字符常量用O替換,字符串常量用s替換; 規(guī)則5:去掉包名,將包名+類名替換成類名; 規(guī)則6:補(bǔ)全調(diào)用者,具體為:對(duì)于一個(gè)對(duì)象調(diào)用自己的方法,且該方法的前面沒(méi)有對(duì)象名或類名時(shí),需將對(duì)象名或類名添加到方法名的前面; 規(guī)則7:將初始化列表中的內(nèi)容替換為空; 規(guī)則8:去掉注釋、包和空格。
3.根據(jù)權(quán)利要求1所述的基于代碼克隆自動(dòng)檢測(cè)和及時(shí)提醒的軟件復(fù)用方法,其特征在于,所述步驟4)中,最長(zhǎng)公共前綴數(shù)組LongestCommonPrefixArray[]中的代碼克隆群為對(duì)應(yīng)的一維數(shù)組TokenArray []中token個(gè)數(shù)大于最小有效token閾值的代碼克隆群。
【文檔編號(hào)】G06F9/44GK104077147SQ201410332613
【公開(kāi)日】2014年10月1日 申請(qǐng)日期:2014年7月11日 優(yōu)先權(quán)日:2014年7月11日
【發(fā)明者】李必信, 劉輝輝, 榮學(xué)益 申請(qǐng)人:東南大學(xué)