當使用指令 -analysis 呼叫時,godoc 會針對它建立索引的 Go 套件執行靜態分析,並在原始程式碼和套件檢視中顯示結果。本文檔提供這些功能的簡要導覽。

類型分析功能

godoc -analysis=type 會執行類似於編譯器所執行的靜態檢查:它偵測格式錯誤的程式,將每個識別碼解析到它所表示的實體,計算每個表達式的類型和每個類型的函式集,並判定哪些類型可指定給哪些介面類型。類型分析相當快速,例如,標準程式庫的>200 個套件大約只需 10 秒即可完成。

編譯器錯誤

如果有任何原始檔包含編譯錯誤,原始程式碼檢視會以紅色突顯錯誤位置。將滑鼠暫留在其上方會顯示錯誤訊息。


識別碼解析

在原始程式碼檢視中,每個參考識別碼都會加上註解,說明它所參考的語言實體:套件、常數、變數、類型、函式或陳述標籤。將滑鼠暫留在識別碼上方會顯示實體的種類和類型(例如 var x intfunc f func(int) string)。



按一下連結即可前往實體定義。


類型資訊:大小/配置、函式集、介面

點選定義命名型別的識別碼,會出現一個面板,顯示命名型別的資訊,包括其大小及位元組的配置、其 方法設定,及其實作關係:型別 T 的集合,可指派到這個型別 U 或從這個型別 U 指派,其中 T 或 U 之一至少為介面。這個範例會顯示關於 net/rpc.methodType 的資訊。

方法設定不只包含型別的宣告方法,也包含從結構的匿名欄位中「提昇」的任何方法,例如這個範例中的 sync.Mutex。此外,接收者型別會顯示為 *TT,依據它是否需要接收者的位址或僅需要一個複製值。

方法設定和實作關係也可以透過套件檢視存取。

指標分析功能

godoc -analysis=pointer 附加執行精確的全程式指標分析。換句話說,它會近似每個參考(不只有類別為 *T 的變數,也包含 []Tfuncmapchaninterface)可能參考的記憶體位置。此資訊會顯示每個動態呼叫(透過 func 變數或介面方法)的可能目標,以及同一通道上傳送及接收作業之間的關係。

與型別分析相比,指標分析需要更多時間和記憶體,而且對於超過一百萬行的程式碼庫而言,這是不切實際的。

呼叫圖形導覽

當指標分析完成時,原始碼檢視會以呼叫者被呼叫者資訊註解程式碼:呼叫者資訊與宣告函式的 func 關鍵字相關聯,而被呼叫者資訊與函式呼叫的開啟括號 '(' 相關聯。

在此範例中,將滑鼠移至 rot13 函式(定義於 strings/strings_test.go)的宣告,可以發現它僅在一個地方被呼叫。

點選連結將導覽至唯一的呼叫者。(如果有多個呼叫者,會先顯示一個選項清單。)

請注意,將滑鼠移至這個呼叫上,會發現此位置有 19 個可能的被呼叫者,其中我們的 rot13 函式只是一個:這是一個透過型別為 func(rune) rune 的變數進行的動態呼叫。點選呼叫會顯示所有 19 個潛在被呼叫者的清單,並以截斷形式顯示。其中許多是匿名函式。

與基於型別的技術相比,指標分析可提供非常精確的呼叫圖近似。舉例來說,下一個範例會顯示 testing 套件內負責呼叫所有使用者定義的名稱為 ExampleXYZ 的函式的動態呼叫。

請回想所有此類函式皆為 func() 類型,亦即沒有參數也沒有結果。基於類型的近似只會得出這個呼叫可能會調用符合該類型的任何函式—而且大多數程式中這種函式非常多—但是指標分析可以追蹤特定 func 值流經測試套件的流程。由於它的精準度,結果只包含名稱以 Example 開頭的函式。

封裝內部呼叫圖

相同呼叫圖資訊在封裝檢視中以非常不同的方式呈現。對於每個封裝,互動樹狀檢視能探索呼叫圖與該封裝相關的方式;所有來自其他封裝的函式都被省略。樹狀結構的根節點為封裝的外部進入點:不僅是其匯出的函式,還有任何從封裝外部(動態)呼叫的非匯出或匿名函式。

此範例顯示 path/filepath 封裝的進入點,其中 Glob 的呼叫圖展開好幾層

請注意,Glob 和 Join 的節點出現好幾次:此樹狀結構是循環圖的部分展開;完整的展開通常是無限的。

對於封裝檢視中記載的每個函式,另一個互動樹狀檢視能探索從該函式開始的相同圖形。這是 net/http.ListenAndServe 內部圖形的一部分。

通道對等方(傳送 ↔ 接收)

由於並行的 Go 程式使用通道傳遞的內容不限於值,還包括不同 goroutine 之間的控制權,因此在閱讀 Go 程式碼時,很自然地會希望從通道傳送導覽到對應的接收,以便了解事件順序。

Godoc 用一個連結註釋每個通道作業(建立、傳送、範圍、接收、關閉),連結的目標面板會顯示其他可能與相同通道建立別名的作業相關資訊。

此範例取自 net/http 測試,顯示在 chan bool 上的傳送處理。

按一下 <- 傳送操作員,會揭露這個通道是在某個唯一位置(第 332 行)建立的,而且有三個接收處理可能會讀取這個值。幾乎不用特別指出,有些通道元素類型非常廣泛地被使用(例如 struct{}、bool、int、interface{}),而且典型的 Go 程式可能包含數十個對型別為 chan bool 的值的接收處理;儘管如此,指標分析仍能比僅根據類型區分出通道上的處理,而達到更精細的精確度。

請注意,傳送發生在一個不同的(匿名)函式中,不同於包含 make 和接收處理的外部函式。

以下是在 net/http 封裝中,另一個在不同 chan bool 上的傳送範例

分析只找到一個接收處理有可能從這個通道接收,在這個功能的測試中。

已知問題

所有分析結果僅與一種組態 (例如 amd64 linux) 相關。根據不同平台或建置標籤條件式編譯的檔案不會在分析中顯示。

需要使用 cgo 工具對 import "C" 檔案進行預處理。預處理後檔案偏移不會與未預處理的檔案對齊,因此標記也會不對齊。

檔案不會定期重新分析。如果運行伺服器底層的檔案變更,顯示的標記將會不對齊。

其他問題列於 tools/godoc/analysis/README