帶有具體參數的通用 API 使用代碼推薦

帶有具體參數的通用 API 使用代碼推薦

引用

Chi Chen and Xin Peng and Jun Sun and Zhenchang Xing and Xin Wang and Yifan Zhao and Hairui Zhang and Wenyun Zhao. Generative API usage code recommendation with parameter concretization. SCIENCE CHINA Information Sciences, 2019, 192103:1--192103:22.

摘要

許多編程語言和開發框架都具有廣泛的庫(例如 JDK 和 Android 庫),如果有效地使用它們可以簡化軟件工程的任務。由於有眾多的庫類,有時還有複雜的 API(應用程序編程接口)使用約束,程序員通常難以記住這些 API 以及正確地使用它們。本研究通過開發名為 DeepAPIRec 的引擎來解決此問題,該引擎會自動推薦 API 使用代碼。與現有產品相比,我們的方法在兩個方面與眾不同。首先,它是基於樹的長期短期記憶(LSTM)神經網絡,受到了機器學習社區的最新發展的啟發。基於樹的 LSTM 神經網絡使我們能夠對可變長度的代碼上下文進行建模和推理,並做出精確的預測。其次,我們應用數據流分析為 API 使用代碼生成具體參數,這不僅使我們能夠生成完整的代碼建議,而且提高了由基於樹的 LSTM 神經網絡的學習結果的準確性。我們已經實現了支持 Java 程序的方法。通過對 JDK 庫的實驗研究表明,在語句級別的推薦下,DeepAPIRec 可以實現大約 37%的 top-1 精度和大約 64%的 top-5 精度,這明顯優於現有方法。我們的用戶研究進一步證實,與 IntelliJ IDEA 相比,DeepAPIRec 可以幫助開發人員更快、更準確地編寫代碼。

1. 介紹

目前已經有許多代碼推薦技術來幫助開發人員開展軟件開發任務。一些技術將開發人員需求的自然語言描述作為輸入,並使用信息檢索技術或深度學習技術來搜索與輸入描述有關的代碼。許多其他技術進一步利用代碼信息,例如 API 使用情況,程序結構(例如,數據或控制流)以及開發人員部分實現的代碼更改,來推薦代碼以完成部分實現。近年來,基於對代碼自然性的觀察,生成代碼推薦方法不斷增長。生成方法從現有代碼中學習編碼模式的某種統計語言模型,例如基於 N-gram 的簡單模型,抑或包含基於圖的代碼結構或歷史修改信息的模型。[基於 N-gram 的模型將源代碼視為基於令牌的序列,並以之前的 N-1 個令牌作為輸入,以產生下一個令牌的候選列表作為輸出。基於圖的模型將源代碼視為圖,並將當前代碼的一組上下文(子)圖作為輸入,以生成候選 API 列表作為輸出。基於更改的模型將代碼更改視為一堆細粒度的原子更改,並將源代碼視為一組代碼令牌。這種模型將代碼更改和代碼上下文作為輸入,以產生候選 API 列表作為輸出。]從理論上講,這些生成方法可以生成新的代碼。

但是,這些方法僅具有有限的建模和生成能力。基於 N-gram 和基於修改的模型僅考慮當前編輯位置之前的令牌中的代碼順序上下文。但是,程序結構(例如數據或控制流)也是重要的上下文信息。此外,開發人員經常遵循非順序的編輯順序,這就要求將代碼上下文擴展到在編輯位置之後的代碼。基於圖的模型考慮程序結構,但均等地對待所有上下文,並且不能有效地對可變長度的代碼上下文建模。這些對建模和生成的限制使採用現有的生成代碼推薦方法變得困難。例如,當前的技術無法生成完整的代碼行,包括具有具體參數的 API 調用或將 API 調用的返回值分配給局部變量。例如,當前的技術可以生成 if 令牌,但無法生成 if(){}語句框架以及 if-condition 和 if-body。

本文提出了一種稱為 DeepAPIRec 的新方法,用於生成 API 使用代碼的推薦,它解決了現有生成代碼推薦方法的侷限性。我們的方法基於基於樹的長期短期記憶(LSTM)神經網絡,該網絡將豐富的代碼信息組織為基於樹的結構,該結構可轉換回源代碼。當生成一些代碼元素時,我們的基於樹的結構可以逐步擴展,從而能夠逐步生成較長的完整代碼行。此外,基於樹的結構以及 LSTM 保留長距離依賴關係的出色能力,使我們能夠對可變長度、前後代碼上下文進行建模和推理。除了基於樹的 LSTM 模型之外,我們的方法還使用數據依賴關係的統計參數模型來確定基於樹的 LSTM 模型推薦的 API 調用的具體參數。

評估實驗結果表明,DeepAPIRec 在語句級別的建議下達到了約 37%的 top-1 精度和約 64%的 top-5 精度,這明顯優於現有方法。此外,我們的敏感性分析表明,上下文中的 API 調用數量和要預測的 API 調用數量的比例對 DeepAPIRec 的預測準確性具有重大影響。但是,待補充代碼的位置對 DeepAPIRec 的有效性影響很小。最後,我們進行了 16 名學生和 5 項任務的用戶研究。結果表明 DeepAPIRec 可以幫助開發人員更準確,更有效地完成編程任務。

本研究做出了以下主要貢獻:

  • 關於 API 使用代碼推薦方法的建議,該方法結合了基於樹的 LSTM 和統計參數模型的優點,以不斷生成完整的代碼行。
  • 在具有 GPU 加速功能的深度學習系統中實施我們的方法,該系統支持對基於 TensorFlow1 和 Fold library2 的基於樹的 LSTM 網絡進行有效的訓練和推理。
  • 對 DeepAPIRec 用於語句預測的準確性進行實驗評估,分析影響語句預測準確性的關鍵因素,並評估 DeepAPIRec 的可用性。

2. 動機

圖 1 展示了一個 Java 代碼示例,該示例代碼結合摘要算法(即從消息創建哈希值,例如 MD5)與加密算法(即使用私鑰對哈希值進行加密,例如 RSA),來簽名一條消息。我們假設開發人員 Bob 知道如何將消息轉換為字節數組,指定簽名算法以及對消息進行簽名。 Bob 憑藉自己的知識能力,在圖 1 中用黑色字體(即第 1-11 行)編寫了部分實現。摘要算法名為 digestAlgorith,需要私鑰 pk 作為輸入。第 2 行代碼將字符串消息轉換為字節數組,第 3–11 行使用私鑰 pk 來調用 digestAlgorith。

在完成這些準備步驟之後,就該對消息進行簽名了。不幸的是,Bob 不知道如何簽名消息,因為他不知道應該使用哪個 API 來完成該程序。我們的 DeepAPIRec 可以推薦帶有合適的具體參數的正確 API 供 Bob 使用。要使用 DeepAPIRec,Bob 只需將第 12 行標記為$hole$,然後請求 DeepAPIRec 的推薦。

帶有具體參數的通用 API 使用代碼推薦

DeepAPIRec 由用於語句預測的深度學習模型(語句模型)和用於參數具體化的統計模型(參數模型)組成。語句模型使用基於樹的 LSTM 來從大量基於 AST 表示的代碼程序庫中學習 API 用法和程序結構模式。基於部分實現代碼中的 API 使用情況和程序結構以及其已經學習的 API 使用模式,該語句模型推斷出$hole$中待填充的代碼很可能是要調用 API java.security.Signature.getInstance(java.lang.String)來獲得簽名對象。實際上,這正是 Bob 在第 12 行中需要做的。

為了使 API 推薦更加完整,DeepAPIRec 使用參數模型來查找 Bob 可以用來調用 API 的最合適的參數。參數模型分析數據依賴關係計算在$hole$之前出現的每個變量或對象被推薦依賴的概率。在此示例中,推斷應使用變量 signMode 調用 java.security.Signature.getInstance(java.lang.String)。最後,DeepAPIRec 為$hole$生成完整的代碼語句行,其中不僅包含 API 調用和具體參數,還包含變量聲明和賦值,即:Signature signature = Signature.getInstance(signMode)。

當然,此行代碼尚未完成程序。Bob 可以繼續將下一行標記為$hole$,然後再次請求 DeepAPIRec 的推薦。DeepAPIRec 可以繼續為第 13 行推薦代碼 signature.initSign(pk),為第 14 行推薦 signature.update(messageByte),為第 15 行提供 byte[] byteArray= signature.sign()。第 12–15 行正確的源代碼如圖 1 所示。我們可以看到 DeepAPIRec 推薦的這些代碼成功地幫助 Bob 完成了該程序。

請注意,DeepAPIRec 嘗試推薦具有適當語法結構和構造的完整代碼聲明行。實際上,當語句模型從基於 AST 的程序表示形式學習程序結構模式時,它還可以推薦程序結構,例如 if(){}語句框架。與僅推薦下一個令牌或下一個 API 調用的現有技術相比,這是代碼推薦技術的一項重大改進。

3. 深度學習模型

我們的研究由最近在深度學習中技術進展促成,例如樹狀結構的長期短期記憶(Tree-LSTM)網絡。Tree-LSTM 網絡通過支持基於樹的語義表示來改進普通的 LSTM 網絡。研究表明,當數據具有自然樹結構時,Tree-LSTM 優於現有的學習模型,包括 LSTM。程序天然具有樹的結構,例如語法樹,這使 Tree-LSTM 成為編碼和 API 使用學習的理想選擇。

LSTM 是一種遞歸神經網絡(RNN),非常適合對數據之間具有長期依賴性的時間序列進行分類,處理和預測。當 LSTM 用於文本處理時,輸入序列和輸出中的所有元素(稱為單詞)都需要包含在詞彙表中。要由 LSTM 處理,所有單詞都需要通過單詞嵌入將其編碼為向量,從而將單詞映射為實數向量。

LSTM 已成功應用於各種序列學習任務,例如語音識別,音樂創作,手寫識別和文本生成。但是,程序中的源代碼具有良好定義的語法和許多級別的語義,其本質上具有基於樹的結構。這些基於樹的語法和語義不能被順序 LSTM 中的線性鏈結構完全捕獲。有證據表明,在某些需要理解句法屬性(例如,語義相關性預測和情感分類)的文本分析任務上,樹結構模型(例如 Tree-LSTM)的效果優於順序 LSTM。

帶有具體參數的通用 API 使用代碼推薦

Tree-LSTM 是 LSTM 到樹狀網絡拓撲的概括。Tree-LSTM 單元的狀態由輸入向量及其所有子單元的狀態組成。Tree-LSTM 有兩個變體,即 Child-Sum Tree-LSTM 和 N-ary Tree-LSTM。圖 2 顯示了由樹節點展開的 Child-Sum Tree-LSTM 網絡。該網絡包含一系列 Tree-LSTM 單元,每個單元都是神經網絡的重複模塊。對於輸入樹中的每個樹節點 j,Tree-LSTM 單元讀取其值並將其映射到 xt,j 表示的向量。然後,輸入的 xt,j,所有子單元中的隱藏狀態(即 ht-1,j, …, ht-1,k)和存儲單元(即 ct-1,j, …, ct-1,k)被饋送到當前的 Tree-LSTM 單元中,以生成新的隱藏狀態 ht,j 和存儲單元 ct,j 。根樹 LSTM 單元的隱藏狀態 hn,1 生成後,將被用於通過 softmax 函數或其他函數產生新的輸出。Tree-LSTM 單元的內部結構如圖 2 虛線所示。與 LSTM 單元不同,Tree-LSTM 單元從其所有子單元中獲取多個隱藏狀態和存儲單元作為輸入。圖 3 顯示了一個 N-ary LSTM 網絡,它類似於 Child-Sum Tree-LSTM 網絡。區別在於:(1)每個父節點最多具有 N 個有序子節點;(2)只有葉節點可以接受輸入。

Child-Sum Tree-LSTM 適用於高分支因子的依賴樹,其中每個節點都可以接受輸入,並且子節點是無序的。N-ary LSTM 適用於分支因子有限的選區樹,其中只有葉節點可以接受輸入,子節點是有序的。我們方法中的代碼樹反映了程序的結構,一方面可能具有較高的分支因子,並且非葉節點可以表示代碼元素(例如 API 調用和控制單元)。另一方面,子節點是有序的,例如條件表達式中 if 的 true 分支,false 分支以及程序的其餘部分。因此,我們將 Child-Sum Tree-LSTM 與 N-ary Tree-LSTM 結合起來作為程序的學習模型。

4. 方法

在本節中,我們介紹方法 DeepAPIRec 的詳細信息。 DeepAPIRec 是一種用於 API 使用代碼推薦的數據驅動方法。 最終目標是根據上下文生成並推薦完整的 API 使用代碼,以減少程序員的工作量。要使用 DeepAPIRec,開發人員需要提供請求位置前後的代碼作為上下文,其中包括一些 API 調用或 API 類的變量聲明。當被請求時,DeepAPIRec 將推薦完整的語句,可能包括變量聲明,賦值,對象創建,API 方法調用或字段訪問以及控制單元。DeepAPIRec 推薦使用不包含子語句的簡單語句。例如,在實現同樣的功能時,推薦兩個簡單的語句 File file = new File(path)和 FileInputStream fileInputStream = new FileInputStream(file),而不是推薦 FileInputStream fileInputStream = new FileInputStream(new File(path))。在推薦控制結構時,DeepAPIRec 首先推薦控制單元,然後推薦其條件,最後是其主體。例如,對於控制結構 if(file.exists({file.delete();}),DeepAPIRec 首先推薦 if(){},然後推薦 file.exists(),最後是 file.delete()。

DeepAPIRec 的整體工作流程如圖 4 所示,包括三個階段:語句模型訓練,參數模型構建和代碼推薦。語句模型訓練階段旨在預測下一條語句。它預處理代碼語料庫中的源代碼,準備一組訓練數據,然後應用基於 Tree-LSTM 的深度學習來訓練用於語句預測的語句模型。參數模型構建階段旨在通過在前一階段生成 API 調用時生成具體參數來完成預測。它從代碼語料庫中分析源代碼,系統地提取數據依賴關係,然後構建用於參數化的統計參數模型。基於這兩個模型,代碼推薦階段將帶有缺失的程序作為輸入,並生成帶有具體參數的排序代碼推薦列表。用戶選擇推薦語句後,代碼推薦過程將繼續,並根據更新後的程序推薦其他語句。

帶有具體參數的通用 API 使用代碼推薦

請注意,語句模型由語句的抽象表示訓練,而抽象表示忽略了具體的變量名稱。參數模型是根據具體語句獨立於語句模型構建的。在代碼推薦階段,語句模型用於預測抽象語句,參數模型用於通過從代碼上下文中識別和評估可用變量或對象來為抽象語句生成具體參數。

4.1 語句模型訓練

此階段旨在獲得一個模型,該模型使我們能夠根據編程上下文環境精確預測下一條語句。 給定一個包含大量代碼語料的代碼庫,在此階段,我們首先從代碼庫中的每個方法中提取一個代碼樹,從提取的代碼樹中生成一組訓練數據,最後,通過深度學習來訓練模型。

4.1.1 代碼樹提取

代碼樹是代碼庫中代碼樣本的表示,並且是用於在後續步驟中訓練 Tree-LSTM 網絡的原始數據。代碼樹中的每個節點代表一個 API 調用,一個控制單元,一個變量聲明或一個賦值。目前忽略了其他類型的語句,例如斷言語句,客戶端方法調用和字段訪問。我們從抽象語法樹(AST)和源代碼的控制流中提取代碼樹。給定一個程序,我們如下系統地構建代碼樹:

帶有具體參數的通用 API 使用代碼推薦

  • 如果第一條語句是表 1 第一欄中列出的類型,並且其主體或條件表達式中包含 API 調用,則我們將根據表 1 中所示的規則創建根節點,子節點和子樹。例如,如果第一個語句是 if 語句,我們將創建根節點 IF 及以下子節點和子樹:條件表達式的 Condition 子樹和代表條件表達式結尾的葉節點 ConditionEnd;然後是真正分支的子樹;子節點 ElseIf 或 Else 及其假分支的子樹以及葉節點 ControlEnd 代表控制單元的末尾;最後是該程序其餘部分的後繼子樹。請注意,如果沒有 ElseIf 或 Else 子樹,則將 ControlEnd 節點添加為 Then 子樹的葉節點。
  • 如果第一條語句是包含 API 調用的條件或表達式,我們將為其第一個 API 調用創建一個根節點,併為程序的其餘部分創建一個子樹。
  • 否則,我們根據表 2 創建一個語句節點,併為程序的其餘部分創建為該語句節點的子樹。

請注意,每個語句在代碼樹中都以抽象的方式表示,例如我們忽略了具體的變量名稱,只記錄了 API 調用的完全限定的類,方法或字段名稱。表 2 中顯示了不同種類的語句的表示。圖 5 中展示了示例代碼樹,該樹表示圖 1 中所示的代碼(標記 12 行為$hole$)。

帶有具體參數的通用 API 使用代碼推薦

在實現方面,我們使用語法分析器來確定方法調用或字段訪問是否為 API 調用,並精確識別目標 API 方法或字段以進行程序元素嵌入。我們使用 Java 提供的反射機制從目標 API 庫(例如 JDK 庫)獲取 API 方法和字段的完整列表。解析源代碼時,我們將目標庫添加到類路徑中。因此,給定源代碼中的方法調用或字段訪問權限,我們可以從解析器中獲取目標類的完全限定名稱,並嘗試將目標方法或字段與 API 列表中的方法或字段進行匹配。給定一個方法調用,我們不僅要考慮方法名稱,還要考慮參數列表的兼容性。如果目標方法或字段匹配,則該方法調用或字段訪問被視為 API 調用;否則,它被視為客戶端方法調用或字段訪問。對於級聯方法調用或字段訪問,例如 java.lang.System.out.println(java.lang.String),我們首先識別其第一部分(即 java.lang.System.out),然後確定它是否為 API 調用。如果是 API 調用,我們將使用反射機制獲取其返回類型(即 java.io.PrintStream),然後將返回類型用作目標類,以識別方法調用或字段訪問的其餘部分(即 java.io.PrintStream.println(java.lang.String))。

4.1.2 訓練數據構造

使用提取的代碼樹,我們可以構造訓練樣本。每個訓練樣本是一對,由不完整的代碼樹(即上下文)和要生成的代碼樹節點(即目標節點)組成。對於從代碼庫中獲得的每棵樹,我們刪除其部分節點(即$hole$),並將其替換為特殊節點 Hole。生成的樹和已刪除節點的根形成訓練樣本。請注意,儘管在我們的方法中一次僅生成一個節點,但是該刪除的代碼可能包含多個語句(因此可能包含多個節點)。

給定代碼樹,樹中的節點以及代表 Hole 節點數量的常數 HS,我們根據 Algorithm 1 生成單個訓練樣本。如果當前節點是控制節點(即 IF,While,DoWhile,For,Foreach,Switch 和 Try / Catch),所有節點的子樹(後繼子樹除外)都將被刪除。否則,僅刪除當前節點。然後,將剩餘子樹的根節點視為當前節點,反覆執行上述過程,直到刪除的節點數達到或超過 HS 或不再剩餘節點為止。最後,將節點替換為 Hole 節點,並返回結果樹,與該節點一起形成訓練樣本。

為構造一組訓練樣本,我們對代碼樹中每個節點執行上述算法,Hole 大小從 1 到 MaxHS-1(其中 MaxHS 是代碼樹中的節點數)不等。為了使語句模型能夠預測程序是否完成(在用一些語句填充空洞之後),我們引入了訓練樣本(tree, End),其中 End 是一個特殊節點,表示每個代碼樹的樹都是完整的。

帶有具體參數的通用 API 使用代碼推薦

4.1.3 語句模型訓練

接下來,我們旨在應用深度學習技術,根據在上一步中構建的訓練樣本來構建語句模型。我們的語句模型結合了 Child-Sum Tree-LSTM 和 N-ary Tree-LSTM 的優點。該模型的整體結構是一個 Child-Sum Tree-LSTM 網絡,而其轉移方程式是從 N-ary Tree-LSTM 改編而成的,以適應節點任意數量的子代。該模型的詞彙表包含訓練樣本中出現的所有 API 方法和字段(包括級聯的 API 調用)。

為了將代碼樹饋送到 Tree-LSTM 網絡,我們需要樹中每個節點的矢量表示。因此,我們通過將詞彙量中的每個維度隨機初始化為特定範圍內的值(例如,從-0.05 到 0.05),將詞彙表中的每個單詞映射到實數的 N 維(例如 50 個)向量。這樣可以將每個訓練樣本中的代碼樹(即代碼生成上下文)轉換為嵌入式代碼樹,樹的每個節點都是嵌入式詞(向量)。

為了訓練語句模型,我們將所有訓練樣本提供給 Tree-LSTM 網絡。對於每個訓練樣本,嵌入式代碼樹通過網絡從輸入層傳播到輸出層以生成輸出。嵌入式代碼樹的結構信息在正向傳播過程中進行編碼。按照自上而下的方式根據嵌入式代碼樹動態展開 Tree-LSTM 網絡,以反映代碼樹的結構。例如,對於圖 5 所示的代碼樹中的 if 節點,為 Tree-LSTM 單元分配了四個子單元,分別代表四個子節點。生成輸出後,Tree-LSTM 網絡將開始反向傳播以更新參數。本研究中採用的梯度下降優化算法是自適應梯度算法(AdaGrad4),它是一種修正的具有每參數學習率的隨機梯度下降方法。持續進行上述過程,直到處理完所有訓練樣本。

4.2 參數模型訓練

在此階段,我們旨在獲得一個模型,該模型使我們能夠基於上下文為預測的 API 調用生成具體參數。我們通過分析推薦的 API 和前面的程序語句之間的數據依賴關係來構造參數模型。直觀地,參數可以是新創建的對象,也可以是先前創建的對象。後一種情況下將形成數據依賴。在代碼庫中分析數據依賴性不僅可以讓我們預測 API 調用的參數,而且還可以幫助改善語句預測(即,無法具體化參數的預測語句不太可能是正確的)。實際上,參數模型的原理是一種啟發式設計,旨在最大程度地提高預測語句與其餘代碼片段之間的聯繫。

4.2.1 數據依賴分析

為了構建參數模型,我們首先在之前提取的代碼樹中標識節點之間的數據依賴性。也就是說,如果兩個節點之間存在直接的數據依賴關係,我們將在它們之間添加一個(虛線)邊。 此外,如果節點代表的語句是變量聲明或賦值語句,則我們用要聲明或分配的變量的名稱標記該節點。圖 6 顯示了圖 1 所示程序的具有數據依賴性的代碼樹。每個節點的變量名(如果節點包含變量名)用紅色標記。

帶有具體參數的通用 API 使用代碼推薦

4.2.2 模型構造

直觀地,參數模型用於預測一條語句與其之前的語句之間的數據依賴關係,從而使我們能夠預測 API 調用的參數。我們通過“計算”代碼樹路徑中兩個節點之間的數據依賴關係來構建參數模型。設 Dependency(n, end, p) 為在所有代碼樹中觀察到路徑 p 的次數,其中 p 為路徑,n 為路徑中的一個節點,end 為路徑的最後一個節點,那麼從節點 n 到 end 都存在數據依賴性。顯然,p 是發生數據依賴關係的上下文。例如,給定圖 6 中的路徑(1)-(2)-(3)-(7),節點 2 和 7 之間的依賴性計數是數據依賴在該路徑中發生的次數。假設在代碼語料庫中,路徑(1)-(2)-(3)-(7)發生了 100 次,其中節點 2 和 7 之間存在 90%的數據依賴,那麼節點 2 和 7 之間的依賴計數是 90。

帶有具體參數的通用 API 使用代碼推薦

其中分子是特定節點 n 在所有上下文(即 AllPaths 中的路徑)上的累積依賴項計數。最後,我們根據 rec 最可能具有數據依賴性的節點,即 dp(n, rec)最大的節點,推薦 rec 的參數。

對於圖 1 中的示例,假設推薦使用語句 java.security.Signature.getInstance(java.lang.String),我們首先使用該語句替換圖 6 中所示的代碼樹中的 Hole 節點。為推薦參數,我們需要計算(1)和(7),(2)和(7)以及(3)和(7)的依賴相關性。首先確定所有上下文,即路徑(1)-(2)-(3)-(7)和(2)-(3)-(7)。然後,對於每個路徑 p,我們獲得依賴性計數 Dependency(1, 7, p),Dependency(2, 7, p)和 Dependency(3, 7, p)。總依賴數 total(rec)是所有路徑和節點的依賴項計數之和。如果 dp(2, 7)是所有數據依賴關係概率中最大的,則我們建議使用 signMode 作為推薦語句的參數。

算法 2 中顯示了詳細的參數推薦算法。給定一個程序,帶有 Hole 標識和語句模型提供的前 N 個推薦,我們將程序轉換為代碼樹 g,並將每個推薦分別作為節點 appendNode 附加到 g 替換 Hole 節點。我們將每個包含 appendNode 的新代碼樹表示為 g'。為了推薦參數,我們分別計算每個節點和 appendNode 之間的依賴概率。我們在第 4 行獲得 Paths(從 g'的根節點到達 appendNode 的路徑集合),並通過從第 5 行到第 8 行的循環來構建 AllPaths。我們初始化地圖 map(node, count)來存儲附加節點的依賴計數,其中 key 表示除 appendNode 之外的節點 n,value 表示 n 與 appendNode 之間的依賴關係計數。接下來,對於 AllPaths 中每個路徑 p,我們獲取每個節點 n 和 appendNode 之間的 Dependency(n, appendNode, p),然後相應地更新映射。對於每個 appendNode,我們從計數中獲取其對應的映射,然後將 map 中的所有計數添加為總數,來表示 appendNode 的總依賴計數。然後,對於 appendNode map 中的每個節點,我們將每個節點的計數結果除以總數即為該節點的依賴概率,該概率用於確定推薦參數。

帶有具體參數的通用 API 使用代碼推薦

請注意,參數模型可用於重新排列推薦的語句。如果可以通過數據依賴關係輕鬆地將推薦的語句(即節點)與前面的語句聯繫起來,那麼它很可能是正確的推薦。令 recs 為語句模型推薦的一組語句。對於每個推薦的語句 rec,我們可以從語句模型中獲得一個概率(語句正確的概率),記作 α(rec)。我們可以從參數模型計算出概率 β(rec),如下所示:

帶有具體參數的通用 API 使用代碼推薦

顯然地,β(rec)通過數據依賴性來衡量推薦語句與先前上下文的關聯,關聯程度越高,推薦的語句就越有可能是正確的。然後,我們根據這兩個概率的加權和對推薦的語句 recs 進行排名:

帶有具體參數的通用 API 使用代碼推薦

其中係數是通過經驗實驗確定的。

4.3 代碼推薦

代碼推薦階段將帶有$Hole$(即程序缺失段)的程序作為輸入,並推薦語句列表以迭代和交互的方式進行填補。在每個迭代中,將為下一條語句生成一組要由用戶檢查和選擇的排序後的推薦。代碼推薦階段首先使用語句預測來生成抽象語句,其中變量和參數被抽象為類型和類,然後使用參數具體化將抽象語句實例化為具體的語句。

語句預測步驟將輸入程序轉換為代碼樹,然後通過遵循語句模型訓練中的過程將其映射到嵌入式代碼樹。然後,該步驟將嵌入式代碼樹輸入到語句模型中,並獲得前 N 條推薦的抽象語句及其正確性概率。參數具體化步驟將每個推薦的抽象語句實例化為一個具體語句。給定一個抽象聲明,該步驟首先識別其中需要具體化的類型和類。對於每種類型或類,該步驟從代碼上下文中標識可用的變量或對象,並將其視為候選對象。對於每個候選者,該步驟使用參數模型來計算從當前語句到它的依賴概率。選擇具有最高相關性概率的變量或對象來具體化類型或類。如果沒有類型或類的候選者,則該步驟將直接使用類型或類的名稱作為參數,並將初始化留給用戶。實例化所有 N 條推薦的抽象語句後,該步驟將根據它們的語句預測和參數具體化概率對推薦的語句重新排序。

最後,返回排名最高的 N 個具體語句作為推薦,供用戶檢查和選擇。

致謝

感謝國家重點研發計劃課題:基於協同編程現場的智能實時質量提升方法與技術(2018YFB1003901)和國家自然科學基金項目:基於可理解信息融合的人機協同移動應用測試研究(61802171)支持!

本文由南京大學軟件學院 2018 級碩士生袁陽陽翻譯轉述。


分享到:


相關文章: