檢視原始碼 xref (工具 v4.1.1)
一個交叉參考工具,用於分析函式、模組、應用程式和發行版本之間的依賴關係。
函式之間的呼叫可以是本機呼叫,例如 f()
,或是外部呼叫,例如 mod:f()
。
模組資料(從 BEAM 檔案中提取)包含本機函式、匯出函式、本機呼叫和外部呼叫。預設情況下,對內建函式 (BIF) 的呼叫會被忽略,但如果此模組某些函式接受的選項 builtins
設定為 true
,則也會包含對 BIF 的呼叫。分析的 OTP 版本決定哪些函式是 BIF。函式物件假設在其建立的位置被呼叫(而不是其他位置)。
未解析的呼叫是指對模組、函式或引數為變數的 apply
或 spawn
的呼叫。範例包括 M:F(a)
、apply(M, f, [a])
和 spawn(m, f(), Args)
。未解析的呼叫表示為變數模組已被原子 '$M_EXPR'
取代,變數函式已被原子 '$F_EXPR'
取代,且變數引數數量已被數字 -1
取代的呼叫。上述範例表示為對 '$M_EXPR':'$F_EXPR'/1
、'$M_EXPR':f/1
和 m:'$F_EXPR'/-1
的呼叫。未解析的呼叫是外部呼叫的子集。
警告
未解析的呼叫會導致模組資料不完整,這表示分析結果可能無效。
應用程式是模組的集合。模組的 BEAM 檔案位於應用程式目錄的 ebin
子目錄中。應用程式目錄的名稱決定應用程式的名稱和版本。
發行版本是位於發行版本目錄的 lib
子目錄中的應用程式集合。在《設計原則》一書中可以閱讀更多關於應用程式和發行版本的資訊。
Xref 伺服器透過名稱識別,名稱是在建立新伺服器時提供的。每個 Xref 伺服器都持有一組發行版本、一組應用程式和一組具有模組資料的模組。Xref 伺服器彼此獨立,所有分析都在單個 Xref 伺服器的上下文中評估(例外的是函式 m/1
和 d/1
,它們根本不使用伺服器)。
當模組加入伺服器時,Xref 伺服器的模式決定從 BEAM 檔案中提取哪些模組資料。使用選項 debug_info
編譯的 BEAM 檔案包含「除錯資訊」,這是程式碼的抽象表示。
在
functions
模式(預設模式)中,會從除錯資訊中提取函式呼叫和行號。在
modules
模式中,如果存在除錯資訊,則會忽略它,但會從 BEAM 檔案的其他部分提取模組之間的依賴關係。modules
模式比functions
模式顯著地節省時間和空間,但可以完成的分析受到限制。
已分析的模組是已新增至 Xref 伺服器及其模組資料的模組。程式庫模組是位於程式庫路徑中提及的某些目錄中的模組。如果某些已分析的模組使用其某些匯出的函式,則表示已使用程式庫模組。未知的模組既不是已分析的模組,也不是程式庫模組,但其匯出的函式被某些已分析的模組使用。
未知的函式是已使用的函式,它既不是任何已分析的模組本機或匯出的函式,也不是任何程式庫模組匯出的函式。未定義的函式是外部使用的函式,它不是任何已分析的模組或程式庫模組匯出的函式。根據此概念,本機函式可能是未定義的函式,也就是說,如果它從某些模組外部使用。所有未知的函式也是未定義的函式;在《使用者指南》中有一個圖表說明這種關係。
模組屬性標籤 deprecated
可以用來通知 Xref 關於已棄用的函式,以及選擇性地通知函式何時計畫移除。以下是一些範例來說明其概念
-deprecated({f,1}).
- 匯出的函式f/1
已棄用。沒有說明是否會移除f/1
。-deprecated({f,1,"Use g/1 instead"}).
- 如上所述,但帶有描述性字串。字串目前未被xref
使用,但其他工具可以使用它。-deprecated({f,'_'}).
- 所有匯出的函式f/0
、f/1
等都已棄用。-deprecated(module).
- 模組中所有匯出的函式都已棄用。等同於-deprecated({'_','_'}).
。-deprecated([{g,1,next_version}]).
- 函式g/1
已棄用,將在下一個版本中移除。-deprecated([{g,2,next_major_release}]).
- 函式g/2
已棄用,將在下一個主要版本中移除。-deprecated([{g,3,eventually}]).
- 函式g/3
已棄用,最終將會移除。-deprecated({'_','_',eventually}).
- 模組中所有匯出的函式都已棄用,最終將會移除。
在進行任何分析之前,必須先設定模組資料。例如,當所有模組資料都已知時,會計算交叉參考和未知函式。需要完整資料的函式(analyze/2,3
、q/2,3
、variables/1,2
會自動處理設定資料。在呼叫任何 add
、replace
、remove
、set_library_path/2,3
或 update/1,2
函式之後,需要(再次)設定模組資料。
設定模組資料的結果是呼叫圖。有向圖由一組頂點和一組(有向)邊緣組成。邊緣表示函式、模組、應用程式或發行版本之間的呼叫(From,To)。From 被視為呼叫 To,而 To 被視為被 From 使用。呼叫圖的頂點是所有模組資料的函式:已分析模組的本機和匯出函式、已使用的 BIF、已使用的程式庫模組的匯出函式,以及未知的函式。編譯器新增的函式 module_info/0,1
包含在匯出的函式中,但僅當從某些模組呼叫時才包含。邊緣是所有模組資料的函式呼叫。由於邊緣是集合,因此如果函式在同一行程式碼中被多次本機或外部使用,則只會有一個邊緣。
呼叫圖由 Erlang 詞彙表示(集合是清單),適用於許多分析。但對於查看呼叫鏈的分析,清單表示法太慢了。改用 digraph
模組提供的表示法。將呼叫圖的清單表示法(或其子圖)轉換為 digraph
表示法並非免費,因此用於表達要描述的查詢的語言具有執行此任務的特殊運算子,並且可以儲存 digraph
表示法以進行後續分析。
除了呼叫圖之外,還有一個圖稱為跨呼叫圖。這是一個呼叫(From,To)的圖,其中在呼叫圖中存在從 From 到 To 的呼叫鏈,並且每個 From 和 To 都是匯出的函式或未使用的本機函式。頂點與呼叫圖的頂點相同。
模組、應用程式和發行版本之間的呼叫也是有向圖。這些圖的頂點和邊緣的類型是(範圍從最特殊到最一般):函式的 Fun
、模組的 Mod
、應用程式的 App
和發行版本的 Rel
。以下段落將描述用於選擇和分析圖表部分的語言的不同結構,首先是常數
- 運算式 ::= 常數
常數 ::= 常數 | 常數
:
類型 | 正規表示式常數 ::= 常數 |
[
常數,
...]
|{
常數,
...}
常數 ::= 呼叫 | 常數
呼叫 ::= FunSpec
->
FunSpec |{
MFA,
MFA}
| AtomConst->
AtomConst |{
AtomConst,
AtomConst}
常數 ::= AtomConst | FunSpec | MFA
AtomConst ::= 應用程式 | 模組 | 發行版本
- FunSpec ::= 模組
:
函式/
元數 - MFA ::=
{
模組,
函式,
元數}
RegExpr ::= RegString
:
類型 | RegFunc | RegFunc:
類型- RegFunc ::= RegModule
:
RegFunction/
RegArity - RegModule ::= RegAtom
- RegFunction ::= RegAtom
RegArity ::= RegString | 數字 |
_
|-1
RegAtom ::= RegString | 原子 |
_
- RegString ::= - 正規表示式,如
re
模組中所述,以雙引號括起來 - 類型 ::=
Fun
|Mod
|App
|Rel
- 函式 ::= 原子
- 應用程式 ::= 原子
- 模組 ::= 原子
- 發行版本 ::= 原子
元數 ::= 數字 |
-1
- 原子 ::= - 與 Erlang 原子相同 -
- 數字 ::= - 與非負 Erlang 整數相同 -
常數的範例包括:kernel
、kernel->stdlib
、[kernel, sasl]
、[pg -> mnesia, {tv, mnesia}] : Mod
。如果 Const
的執行個體不符合任何圖表的任何頂點,則會發生錯誤。如果有多個頂點符合 AtomConst
的未類型執行個體,則會選擇最一般的類型。常數清單會被解讀為一組常數,所有常數的類型都相同。常數的元組構成呼叫鏈(可能但不一定對應於某些圖表的實際呼叫鏈)。為 Constant
的清單或元組指定類型等同於為每個 Constant
指定類型。
正規表示式 用於選取圖形中的部分頂點。一個 RegExpr
由一個 RegString
和一個類型組成,例如 "xref_.*" : Mod
,它會被解讀為符合該表示式的所有模組(或應用程式或發行版本,取決於類型)。類似地,RegFunc
會被解讀為符合該表示式的呼叫圖的頂點。例如 "xref_.*":"add_.*"/"(2|3)"
,它會匹配任何 xref 模組中參數數量為 2 或 3 的所有 add
函數。另一個範例,匹配參數數量為 10 或以上的函數:_:_/"[1-9].+"
。這裡的 _
是 ".*"
的縮寫,也就是匹配任何內容的正規表示式。
變數 的語法很簡單
- 表達式 ::= 變數
- 變數 ::= - 與 Erlang 變數相同 -
變數有兩種
預定義變數 - 儲存模組資料,無法被賦值,只能在查詢中使用。
使用者變數 - 可以被賦值,通常用於評估查詢時的暫時結果,以及儲存查詢結果以供後續查詢使用。
預定義變數如下(標記 (*) 的變數僅在 functions
模式下可用)
E
- 呼叫圖邊緣 (*)。V
- 呼叫圖頂點 (*)。M
- 模組。所有模組:已分析的模組、使用的程式庫模組和未知的模組。A
- 應用程式。R
- 發行版本。ME
- 模組邊緣。所有模組呼叫。AE
- 應用程式邊緣。所有應用程式呼叫。RE
- 發行版本邊緣。所有發行版本呼叫。L
- 本地函數 (*)。所有已分析模組的本地函數。X
- 匯出函數。所有已分析模組的匯出函數和所有使用的程式庫模組的匯出函數。F
- 函數 (*)。B
- 使用的 BIF。如果所有已分析模組的builtins
皆為false
,則B
為空。U
- 未知函數。UU
- 未使用的函數 (*)。所有已分析模組中未被使用的本地和匯出函數。XU
- 外部使用的函數。所有模組的函數,包括在某些外部呼叫中使用的本地函數。LU
- 本地使用的函數 (*)。所有模組中在某些本地呼叫中使用的函數。OL
- 具有on_load
屬性標籤的函數 (*)。LC
- 本地呼叫 (*)。XC
- 外部呼叫 (*)。AM
- 已分析的模組。UM
- 未知的模組。LM
- 使用的程式庫模組。UC
- 未解析的呼叫。在modules
模式下為空。EE
- 內部呼叫圖邊緣 (*)。DF
- 已棄用的函數。所有已棄用的匯出函數和所有使用過的已棄用 BIF。DF_1
- 已棄用的函數。所有將在下一個版本中移除的已棄用函數。DF_2
- 已棄用的函數。所有將在下一個版本或下一個主要版本中移除的已棄用函數。DF_3
- 已棄用的函數。所有將在下一個版本、下一個主要版本或之後的版本中移除的已棄用函數。
以下是關於預定義變數的一些 事實(集合運算子 +
(聯集)和 -
(差集)以及轉換運算子 (
Type)
將在下文說明)
F
等於L + X
。V
等於X + L + B + U
,其中X
、L
、B
和U
成對不相交(也就是說,沒有共同元素)。UU
等於V - (XU + LU)
,其中LU
和XU
可能有共同元素。換句話說V
等於UU + XU + LU
。OL
是F
的子集。E
等於LC + XC
。請注意,如果某些函數同時在本地和外部被同一個函數使用,則LC
和XC
可能有共同元素。U
是XU
的子集。B
是XU
的子集。LU
等於range LC
。XU
等於range XC
。LU
是F
的子集。UU
是F
的子集。range UC
是U
的子集。M
等於AM + LM + UM
,其中AM
、LM
和UM
成對不相交。ME
等於(Mod) E
。AE
等於(App) E
。RE
等於(Rel) E
。(Mod) V
是M
的子集。如果所有已分析的模組都有一些本地、匯出或未知函數,則等式成立。(App) M
是A
的子集。如果所有應用程式都有某些模組,則等式成立。(Rel) A
是R
的子集。如果所有發行版本都有某些應用程式,則等式成立。DF_1
是DF_2
的子集。DF_2
是DF_3
的子集。DF_3
是DF
的子集。DF
是X + B
的子集。
一個重要的概念是表達式的轉換。轉換表達式的語法是
- 表達式 ::=
(
類型)
表達式
轉換運算子的解釋取決於指定的類型 Type
、Expression
的類型,以及 Expression
解釋元素的結構。如果指定的類型等於表達式類型,則不進行轉換。否則,轉換會一步一步地進行;例如,(Fun) (App) RE
等效於 (Fun) (Mod) (App) RE
。現在假設 Expression
的解釋是一組常數(函數、模組、應用程式或發行版本)。如果指定的類型比表達式類型更通用,例如分別為 Mod
和 Fun
,則轉換表達式的解釋是具有至少一個在表達式解釋中提到的函數的模組集合。如果指定的類型比表達式類型更特殊,例如分別為 Fun
和 Mod
,則解釋是模組的所有函數的集合(在 modules
模式下,轉換是部分的,因為本地函數是未知的)。應用程式和發行版本的轉換方式類似。例如,(App) "xref_.*" : Mod
返回所有包含至少一個模組的應用程式,使得 xref_
是模組名稱的前綴。
現在假設 Expression
的解釋是一組呼叫。如果指定的類型比表達式類型更通用,例如分別為 Mod
和 Fun
,則轉換表達式的解釋是呼叫集合 (M1, M2),使得表達式的解釋包含從 M1 的某些函數到 M2 的某些函數的呼叫。如果指定的類型比表達式類型更特殊,例如分別為 Fun
和 Mod
,則解釋是所有函數呼叫 (F1, F2) 的集合,使得表達式的解釋包含呼叫 (M1, M2),且 F1 是 M1 的函數,F2 是 M2 的函數(在 modules
模式下,沒有函數呼叫,因此轉換為 Fun
始終會產生空集合)。同樣,應用程式和發行版本的轉換方式類似。
常數和變數的解釋是集合,這些集合可用作藉由套用集合運算子來形成新集合的基礎。語法為
- 表達式 ::= 表達式 二元集合運算 表達式
二元集合運算 ::=
+
|*
|-
+
、*
和 -
分別被解釋為聯集、交集和差集:兩個集合的聯集包含兩個集合的所有元素;兩個集合的交集包含兩個集合的共同元素;而兩個集合的差集包含第一個集合中不屬於第二個集合的元素。兩個集合的元素必須具有相同的結構;例如,函數呼叫不能與函數組合。但是,如果轉換運算子可以使元素相容,則更通用的元素會被轉換為不太通用的元素類型。例如,M + F
等效於 (Fun) M + F
,而 E - AE
等效於 E - (Fun) AE
。再舉一個例子:X * xref : Mod
被解釋為模組 xref
匯出的函數集合;xref : Mod
會被轉換為 X
的更特殊類型(也就是 Fun
),產生 xref
的所有函數,並且與 X
(已分析的模組和程式庫模組匯出的所有函數)的交集會被解釋為由某些模組匯出且為 xref
的函數。
還有單元集合運算子
- Expression ::= UnarySetOp Expression
UnarySetOp ::=
domain
|range
|strict
回想一下,呼叫是一對 (From, To)。domain
應用於一組呼叫時,會被解釋為所有頂點 From 的集合,而 range
則被解釋為所有頂點 To 的集合。 strict
運算子的解釋是移除所有 (A, A) 形式的呼叫的操作數。
限制運算子的解釋是第一個運算元(一組呼叫)的子集。第二個運算元(一組頂點)會被轉換為第一個運算元的類型。限制運算子的語法為:
- Expression ::= Expression RestrOp Expression
- RestrOp ::=
|
- RestrOp ::=
||
- RestrOp ::=
|||
以下詳細說明三個運算子的解釋
|
- 來自任何頂點的呼叫子集。||
- 呼叫到任何頂點的呼叫子集。|||
- 呼叫到和來自任何頂點的呼叫子集。對於所有呼叫集合CS
和所有頂點集合VS
,CS ||| VS
等同於CS | VS * CS || VS
。
如果兩個函式(模組、應用程式、發行版本)彼此(間接)呼叫,則它們屬於同一個強連通元件。components
運算子的解釋是一組呼叫的強連通元件集合。一組呼叫的condensation
是一組新的強連通元件之間的呼叫,如果第一個元件的某個常數呼叫第二個元件的某個常數,則兩個元件之間存在邊。
of
運算子的解釋是第二個運算元(一組呼叫)的呼叫鏈,該鏈會依給定順序遍歷第一個運算元(一組常數)的所有頂點。第二個運算元會被轉換為第一個運算元的類型。例如,of
運算子可用於找出某個函式是否間接呼叫另一個函式,以及呼叫鏈如何展示此呼叫。圖形分析運算子的語法為:
- Expression ::= Expression BinaryGraphOp Expression
- Expression ::= UnaryGraphOp Expression
UnaryGraphOp ::=
components
|condensation
- BinaryGraphOp ::=
of
如前所述,圖形分析作用於圖的 digraph
表示法。預設情況下,digraph
表示法會在需要時建立(並在不再使用時刪除),但也可以透過使用 closure
運算子顯式建立。
- Expression ::= ClosureOp Expression
- ClosureOp ::=
closure
closure
運算子的解釋是運算元的傳遞閉包。
限制運算子也為閉包定義; closure E | xref : Mod
被解釋為來自 xref
模組的直接或間接函式呼叫,而 E | xref : Mod
的解釋是來自 xref
的直接呼叫集合。如果某個圖形要在多個圖形分析中使用,將圖形的 digraph
表示法指定給使用者變數,然後確保每個圖形分析都對該變數而不是圖形的列表表示法進行操作,這樣可以節省時間。
在 functions
模式下,可以使用定義函式的行(更準確地說:第一個子句開始的行)和使用函式的行。行號指的是定義函式所在的檔案。這也適用於使用 -include
和 -include_lib
指令包含的檔案,這可能會導致函式明顯定義在同一行。行運算子用於將行號指定給函式,並將行號集合指定給函式呼叫。語法類似於類型轉換運算子:
- Expression ::=
(
LineOp)
Expression - Expression ::=
(
XLineOp)
Expression LineOp ::=
Lin
|ELin
|LLin
|XLin
- XLineOp ::=
XXL
應用於一組函式的 Lin
運算子的解釋是將函式定義所在的行號指定給每個函式。未知函式和程式庫模組的函式會被指定數字 0。
應用於一組函式呼叫的某些 LineOp 運算子的解釋是將第一個函式呼叫第二個函式所在的行號集合指定給每個呼叫。並非所有運算子都會將行號指定給所有呼叫。
Lin
運算子為呼叫圖邊緣定義;LLin
運算子為本地呼叫定義。XLin
運算子為外部呼叫定義。ELin
運算子為內部呼叫圖邊緣定義。
Lin
(LLin
,XLin
)運算子指定呼叫(本地呼叫,外部呼叫)所在的行。ELin
運算子將每個呼叫 (From, To) (為其定義)的每個行 L 指定為存在從 From 到 To 的呼叫鏈,並以行 L 上的呼叫開始。
XXL
運算子為應用於一組函式呼叫的任何 LineOp 運算子的解釋定義。結果是用帶有行號的函式呼叫替換函式呼叫,也就是說,呼叫的兩個函式中的每一個都被替換為函式及其定義所在的行的配對。XXL
運算子的效果可以被 LineOp 運算子取消。例如,(Lin) (XXL) (Lin) E
等同於 (Lin) E
。
+
、-
、*
和 #
運算子為行號表示式定義,前提是運算元相容。LineOp 運算子也為模組、應用程式和發行版本定義;運算元會隱式轉換為函式。同樣地,類型轉換運算子為 LineOp 運算子的解釋定義。
計數運算子的解釋是一組元素的數量。該運算子對閉包未定義。+
、-
和 *
運算子在應用於數字時,會被解釋為顯而易見的算術運算子。計數運算子的語法為:
- Expression ::= CountOp Expression
- CountOp ::=
#
所有二元運算子都是左關聯的;例如,A | B || C
等同於 (A | B) || C
。以下是所有運算子的列表,依優先順序遞增排序:
+
,-
*
#
|
,||
,|||
of
(
Type)
closure
、components
、condensation
、domain
、range
、strict
括號用於分組,可以使表示式更易讀或覆寫運算子的預設優先順序。
- Expression ::=
(
Expression)
查詢是非空的語句序列。語句可以是使用者變數的指定或表示式。指定的數值是右手邊表示式的數值。將純表示式放在查詢中的最後一個位置之外的任何其他位置是沒有意義的。查詢的語法由以下產生式概述:
- Query ::= Statement
,
... Statement ::= Assignment | Expression
Assignment ::= Variable
:=
Expression | Variable=
Expression
除非先移除變數,否則無法為變數指定新值。由 =
運算子指定的變數會在查詢結束時移除,而由 :=
運算子指定的變數只能透過呼叫 forget
來移除。當需要重新設定模組資料時,沒有使用者變數;如果呼叫任何使必須再次設定模組資料的函式,則會忘記所有使用者變數。
另請參閱
摘要
類型
-type add_dir_rsn() :: {file_error, file(), file_error()} | {invalid_filename, term()} | {invalid_options, term()} | {unrecognized_file, file()} | beam_lib:chnk_rsn().
-type add_mod_rsn() :: {file_error, file(), file_error()} | {invalid_filename, term()} | {invalid_options, term()} | {module_clash, {module(), file(), file()}} | {no_debug_info, file()} | beam_lib:chnk_rsn().
-type analysis() :: undefined_function_calls | undefined_functions | locals_not_used | exports_not_used | deprecated_function_calls | {deprecated_function_calls, DeprFlag :: depr_flag()} | deprecated_functions | {deprecated_functions, DeprFlag :: depr_flag()} | {call, FuncSpec :: func_spec()} | {use, FuncSpec :: func_spec()} | {module_call, ModSpec :: mod_spec()} | {module_use, ModSpec :: mod_spec()} | {application_call, AppSpec :: app_spec()} | {application_use, AppSpec :: app_spec()} | {release_call, RelSpec :: rel_spec()} | {release_use, RelSpec :: rel_spec()}.
-type answer() :: false | [constant()] | [(Call :: call()) | (ComponentCall :: {component(), component()})] | [Component :: component()] | non_neg_integer() | [DefineAt :: define_at()] | [CallAt :: {funcall(), LineNumbers :: [non_neg_integer()]}] | [AllLines :: {{define_at(), define_at()}, LineNumbers :: [non_neg_integer()]}].
-type app_spec() :: application() | [application()].
-type application() :: atom().
-type component() :: [constant()].
-type constant() :: xmfa() | module() | application() | release().
-type define_at() :: {xmfa(), LineNumber :: non_neg_integer()}.
-type depr_flag() :: next_version | next_major_release | eventually.
-type directory() :: atom() | file:filename().
-type file() :: file:filename().
-type file_error() :: atom().
-type function_name() :: atom().
-type info() :: {application, Application :: [application()]} | {builtins, boolean()} | {directory, directory()} | {library_path, library_path()} | {mode, mode()} | {no_analyzed_modules, non_neg_integer()} | {no_applications, non_neg_integer()} | {no_calls, {NoResolved :: non_neg_integer(), NoUnresolved :: non_neg_integer()}} | {no_function_calls, {NoLocal :: non_neg_integer(), NoResolvedExternal :: non_neg_integer(), NoUnresolved :: non_neg_integer()}} | {no_functions, {NoLocal :: non_neg_integer(), NoExternal :: non_neg_integer()}} | {no_inter_function_calls, non_neg_integer()} | {no_releases, non_neg_integer()} | {release, Release :: [release()]} | {version, Version :: [non_neg_integer()]}.
-type library() :: atom().
-type library_path() :: path() | code_path.
-type mode() :: functions | modules.
-type path() :: [file()].
-type release() :: atom().
-type string_position() :: pos_integer().
-type variable() :: atom().
-type xarity() :: arity() | -1.
-type xmfa() :: {module(), function_name(), xarity()}.
函式
-spec add_application(XrefServer, Directory) -> {ok, application()} | {error, module(), Reason} when XrefServer :: xref(), Directory :: directory(), Reason :: {application_clash, {application(), directory(), directory()}} | add_dir_rsn().
-spec add_application(XrefServer, Directory, Options) -> {ok, application()} | {error, module(), Reason} when XrefServer :: xref(), Directory :: directory(), Options :: Option | [Option], Option :: {builtins, boolean()} | {name, application()} | {verbose, boolean()} | {warnings, boolean()} | builtins | verbose | warnings, Reason :: {application_clash, {application(), directory(), directory()}} | add_dir_rsn().
將應用程式、應用程式的模組,以及模組的模組資料新增至 Xref 伺服器。
這些模組將會是應用程式的成員。預設是使用目錄的基本名稱,並移除版本號作為應用程式名稱,但可以使用 name
選項覆寫。回傳應用程式的名稱。
如果給定的目錄有一個名為 ebin
的子目錄,則會在該目錄中搜尋模組(BEAM 檔案),否則會在給定的目錄中搜尋模組。
-spec add_directory(XrefServer, Directory) -> {ok, Modules} | {error, module(), Reason} when XrefServer :: xref(), Directory :: directory(), Modules :: [module()], Reason :: {application_clash, {application(), directory(), directory()}} | add_dir_rsn().
-spec add_directory(XrefServer, Directory, Options) -> {ok, Modules} | {error, module(), Reason} when XrefServer :: xref(), Directory :: directory(), Options :: Option | [Option], Option :: {builtins, boolean()} | {recurse, boolean()} | {verbose, boolean()} | {warnings, boolean()} | builtins | recurse | verbose | warnings, Modules :: [module()], Reason :: add_dir_rsn().
將指定目錄中找到的模組以及模組的資料新增至 Xref 伺服器。
預設不會檢查子目錄,但如果選項 recurse
的值為 true
,則會在所有層級的子目錄以及給定的目錄中搜尋模組。回傳已加入模組名稱的排序列表。
加入的模組不會是任何應用程式的成員。
-spec add_module(XrefServer, File) -> {ok, module()} | {error, module(), Reason} when XrefServer :: xref(), File :: file:filename(), Reason :: add_mod_rsn().
-spec add_module(XrefServer, File, Options) -> {ok, module()} | {error, module(), Reason} when XrefServer :: xref(), File :: file:filename(), Options :: Option | [Option], Option :: {builtins, boolean()} | {verbose, boolean()} | {warnings, boolean()} | builtins | verbose | warnings, Reason :: add_mod_rsn().
此模組不會是任何應用程式的成員。回傳模組的名稱。
如果 Xref 伺服器的模式為 functions
,且 BEAM 檔案不包含除錯資訊,則會回傳錯誤訊息 no_debug_info
。
-spec add_release(XrefServer, Directory, Options) -> {ok, release()} | {error, module(), Reason} when XrefServer :: xref(), Directory :: directory(), Options :: Option | [Option], Option :: {builtins, boolean()} | {name, release()} | {verbose, boolean()} | {warnings, boolean()} | builtins | verbose | warnings, Reason :: {application_clash, {application(), directory(), directory()}} | {release_clash, {release(), directory(), directory()}} | add_dir_rsn().
將發行版本、發行版本的應用程式、應用程式的模組,以及模組的模組資料新增至 Xref 伺服器。
這些應用程式將會是版本的成員,而模組將會是應用程式的成員。預設是使用目錄的基本名稱作為版本名稱,但可以使用 name
選項覆寫。回傳版本的名稱。
如果給定的目錄有一個名為 lib
的子目錄,則該目錄中的目錄會被視為應用程式目錄,否則給定目錄的所有子目錄都會被視為應用程式目錄。如果有同一個應用程式的多個版本,則會選擇版本最高的那個。
-spec analyze(XrefServer, Analysis) -> {ok, Answer} | {error, module(), Reason} when XrefServer :: xref(), Analysis :: analysis(), Answer :: [term()], Reason :: analyze_rsn().
-spec analyze(XrefServer, Analysis, Options) -> {ok, Answer} | {error, module(), Reason} when XrefServer :: xref(), Analysis :: analysis(), Options :: Option | [Option], Option :: {verbose, boolean()} | verbose, Answer :: [term()], Reason :: analyze_rsn().
根據選擇的分析,回傳 call/0
或 constant/0
的已排序且不重複的列表。在所有已分析模組上運作的預定義分析如下(標記 (*) 的分析僅在模式 functions
中可用)
undefined_function_calls
(*) - 回傳呼叫未定義函式的列表。undefined_functions
- 回傳未定義函式的列表。locals_not_used
(*) - 回傳未在本地使用的本地函式列表。exports_not_used
- 回傳未在外部使用的匯出函式列表。請注意,在modules
模式下,永遠不會將M:behaviour_info/1
報告為未使用。deprecated_function_calls
(*) - 回傳對已棄用函式進行外部呼叫的列表。{deprecated_function_calls, DeprFlag}
(*) - 回傳對已棄用函式進行外部呼叫的列表。如果DeprFlag
等於next_version
,則會回傳呼叫將在下一個版本中移除的函式。如果DeprFlag
等於next_major_release
,則會回傳呼叫將在下一個主要版本中移除的函式,以及呼叫將在下一個版本中移除的函式。最後,如果DeprFlag
等於eventually
,則會回傳所有對要移除的函式進行的呼叫,包括對下一個版本或下一個主要版本中要移除的函式的呼叫。deprecated_functions
- 回傳在外部使用的已棄用函式的列表。{deprecated_functions, DeprFlag}
- 回傳在外部使用的已棄用函式的列表。如果DeprFlag
等於next_version
,則會回傳將在下一個版本中移除的函式。如果DeprFlag
等於next_major_release
,則會回傳將在下一個主要版本中移除的函式,以及將在下一個版本中移除的函式。最後,如果DeprFlag
等於eventually
,則會回傳所有要移除的函式,包括在下一個版本或下一個主要版本中要移除的函式。{call, FuncSpec}
(*) - 回傳由某些給定函式呼叫的函式列表。{use, FuncSpec}
(*) - 回傳使用某些給定函式的函式列表。{module_call, ModSpec}
- 回傳由某些給定模組呼叫的模組列表。{module_use, ModSpec}
- 回傳使用某些給定模組的模組列表。{application_call, AppSpec}
- 回傳由某些給定應用程式呼叫的應用程式列表。{application_use, AppSpec}
- 回傳使用某些給定應用程式的應用程式列表。{release_call, RelSpec}
- 回傳由某些給定版本呼叫的版本列表。{release_use, RelSpec}
- 回傳使用某些給定版本的版本列表。
-spec d(Directory) -> [DebugInfoResult] | [NoDebugInfoResult] | {error, module(), Reason} when Directory :: directory(), DebugInfoResult :: {deprecated, [funcall()]} | {undefined, [funcall()]} | {unused, [mfa()]}, NoDebugInfoResult :: {deprecated, [xmfa()]} | {undefined, [xmfa()]}, Reason :: {file_error, file(), file_error()} | {invalid_filename, term()} | {unrecognized_file, file()} | beam_lib:chnk_rsn().
檢查指定目錄中找到的模組是否有呼叫已棄用的函式、呼叫未定義的函式,以及是否有未使用的本機函式。
程式碼路徑會被用作程式庫路徑。
如果找到的某些 BEAM 檔案包含除錯資訊,則會檢查這些模組並回傳元組列表。每個元組的第一個元素是下列其中之一:
deprecated
,第二個元素是對已棄用函式的排序呼叫列表;undefined
,第二個元素是對未定義函式的排序呼叫列表;unused
,第二個元素是未使用的本地函式的排序列表。
如果沒有 BEAM 檔案包含除錯資訊,則會回傳元組列表。每個元組的第一個元素是下列其中之一:
deprecated
,第二個元素是在外部使用的已棄用函式的排序列表;undefined
,第二個元素是未定義函式的排序列表。
-spec forget(XrefServer) -> ok when XrefServer :: xref().
-spec format_error(Error) -> io_lib:chars() when Error :: {error, module(), Reason :: term()}.
給定此模組的任何函式傳回的錯誤,函式 format_error
會傳回以英文描述錯誤的字串。
對於檔案錯誤,會呼叫函式 file:format_error/1
。
-spec get_default(XrefServer) -> [{Option, Value}] when XrefServer :: xref(), Option :: builtins | recurse | verbose | warnings, Value :: boolean().
傳回所有選項及其預設值的清單。
-spec get_default(XrefServer, Option) -> {ok, Value} | {error, module(), Reason} when XrefServer :: xref(), Option :: builtins | recurse | verbose | warnings, Value :: boolean(), Reason :: {invalid_options, term()}.
傳回選項 Option
的預設值。
-spec get_library_path(XrefServer) -> {ok, LibraryPath} when XrefServer :: xref(), LibraryPath :: library_path().
傳回程式庫路徑。
info/1
函式以某種順序傳回關於 Xref 伺服器的狀態和模組資料的資訊,作為成對的清單 {Tag, term()}
。
info/1
會回傳具有以下標籤的資訊(標記 (*) 的標籤僅在 functions
模式中可用)
-spec info(XrefServer, Category) -> [{Item, [Info]}] | {error, module(), {no_such_info, Category}} when XrefServer :: xref(), Category :: modules | applications | releases | libraries, Item :: module() | application() | release() | library(), Info :: info().
傳回屬於 Category
類別的所有項目的資訊。詳細資訊請參閱 info/3
。
-spec info(XrefServer, Category, Items) -> [{Item, [Info]}] | {error, module(), Reason} when XrefServer :: xref(), Category :: modules | applications | releases | libraries, Items :: Item | [Item], Item :: module() | application() | release() | library(), Info :: info(), Reason :: {no_such_application, Item} | {no_such_info, Category} | {no_such_library, Item} | {no_such_module, Item} | {no_such_release, Item}.
info
函式以某種順序傳回關於 Xref 伺服器的狀態和模組資料的資訊,作為成對的清單 {Tag, term()}
。
info/2
和 info/3
會回傳有關 Xref 伺服器的所有或某些已分析模組、應用程式、版本或程式庫模組的資訊。以下資訊會針對每個已分析模組回傳:
application
,如果模組不屬於任何應用程式,則為空列表,否則為應用程式名稱的列表;builtins
,是否在模組的資料中包含對 BIF 的呼叫;directory
,模組的 BEAM 檔案所在的目錄;no_calls
(*),呼叫數量,將不同行中的一個函式呼叫實例視為個別呼叫;no_function_calls
(*),本地呼叫、已解析的外部呼叫和未解析呼叫的數量;no_functions
(*),本地和匯出函式的數量;no_inter_function_calls
(*),函式間呼叫圖的呼叫數量;
以下資訊會針對每個應用程式回傳:
directory
,模組的 BEAM 檔案所在的目錄;no_analyzed_modules
,已分析模組的數量;no_calls
(*),應用程式模組的呼叫數量,將不同行中的一個函式呼叫實例視為個別呼叫;no_function_calls
(*),應用程式模組的本地呼叫、已解析的外部呼叫和未解析呼叫的數量;no_functions
(*),應用程式模組的本地和匯出函式的數量;no_inter_function_calls
(*),應用程式模組的函式間呼叫圖的呼叫數量;release
,如果應用程式不屬於任何版本,則為空列表,否則為版本名稱的列表;version
,應用程式的版本,以數字列表表示。例如,目錄 "kernel-2.6" 會產生應用程式名稱kernel
和應用程式版本 [2,6];"kernel" 會產生名稱kernel
和版本 []。
以下資訊會針對每個版本回傳:
directory
,版本目錄;no_analyzed_modules
,已分析模組的數量;no_applications
,應用程式的數量;no_calls
(*), 釋出版本模組的呼叫次數,將一個函數在不同行中的呼叫視為個別的呼叫;no_function_calls
(*), 釋出版本模組的本地呼叫、已解析的外部呼叫和未解析的呼叫次數;no_functions
(*), 釋出版本模組的本地和匯出函數的數量;no_inter_function_calls
(*), 釋出版本模組的跨函數呼叫圖 (Inter Call Graph) 的呼叫次數。
以下資訊會針對每個函式庫模組回傳
directory
,函式庫模組的 BEAM 檔案所在的目錄。
對於 no_
標籤回傳的每個呼叫次數、函數數量等等,都有一個查詢會回傳相同的數字。以下列出此類查詢的範例。有些查詢會回傳兩個或多個 no_
標籤數字的總和。mod
( app
、rel
) 指的是任何模組 (應用程式、釋出版本)。
no_analyzed_modules
"# AM"
(info/1)"# (Mod) app:App"
(應用程式)"# (Mod) rel:Rel"
(釋出版本)
no_applications
"# A"
(info/1)
no_calls
。已解析和未解析呼叫的總和"# (XLin) E + # (LLin) E"
(info/1)"T = E | mod:Mod, # (LLin) T + # (XLin) T"
(模組)"T = E | app:App, # (LLin) T + # (XLin) T"
(應用程式)"T = E | rel:Rel, # (LLin) T + # (XLin) T"
(釋出版本)
no_functions
。函式庫模組中的函數和module_info/0,1
函數不會被info
計算在內。假設"Extra := _:module_info/\"(0|1)\" + LM"
已經被評估,則本地和匯出函數的總和為"# (F - Extra)"
(info/1)"# (F * mod:Mod - Extra)"
(模組)"# (F * app:App - Extra)"
(應用程式)"# (F * rel:Rel - Extra)"
(釋出版本)
no_function_calls
。本地呼叫、已解析的外部呼叫和未解析的呼叫的總和"# LC + # XC"
(info/1)"# LC | mod:Mod + # XC | mod:Mod"
(模組)"# LC | app:App + # XC | app:App"
(應用程式)"# LC | rel:Rel + # XC | mod:Rel"
(釋出版本)
no_inter_function_calls
"# EE"
(info/1)"# EE | mod:Mod"
(模組)"# EE | app:App"
(應用程式)"# EE | rel:Rel"
(釋出版本)
no_releases
"# R"
(info/1)
-spec m(FileOrModule) -> [DebugInfoResult] | [NoDebugInfoResult] | {error, module(), Reason} when FileOrModule :: file:filename() | module(), DebugInfoResult :: {deprecated, [funcall()]} | {undefined, [funcall()]} | {unused, [mfa()]}, NoDebugInfoResult :: {deprecated, [xmfa()]} | {undefined, [xmfa()]}, Reason :: {cover_compiled, Module :: module()} | {file_error, file(), file_error()} | {interpreted, Module :: module()} | {invalid_filename, term()} | {no_such_module, Module :: module()} | beam_lib:chnk_rsn().
檢查給定的 BEAM 檔案(帶或不帶 .beam
副檔名)或透過呼叫 code:which(Module)
找到的檔案是否有呼叫已棄用的函式、呼叫未定義的函式,以及是否有未使用的本機函式。
程式碼路徑會被用作程式庫路徑。
如果 BEAM 檔案包含除錯資訊,則會回傳一個元組列表。每個元組的第一個元素是以下其中之一
deprecated
,第二個元素是對已棄用函式的排序呼叫列表;undefined
,第二個元素是對未定義函式的排序呼叫列表;unused
,第二個元素是未使用的本地函式的排序列表。
如果 BEAM 檔案不包含除錯資訊,則會回傳一個元組列表。每個元組的第一個元素是以下其中之一
deprecated
,第二個元素是在外部使用的已棄用函式的排序列表;undefined
,第二個元素是未定義函式的排序列表。
-spec q(XrefServer, Query, Options) -> {ok, Answer} | {error, module(), Reason} when XrefServer :: xref(), Query :: string() | atom(), Options :: Option | [Option], Option :: {verbose, boolean()} | verbose, Answer :: answer(), Reason :: q_rsn().
在 Xref 伺服器的內容中評估查詢,並傳回最後一個陳述式的值。
值的語法取決於表達式
- 一組呼叫由一個已排序且不重複的
call/0
列表表示。 - 一組常數由一個已排序且不重複的
constant/0
列表表示。 - 一組強連通分量是已排序且不重複的
Component
列表。 - 一組強連通分量之間的呼叫是已排序且不重複的
ComponentCall
列表。 - 呼叫鏈由
constant/0
列表表示。該列表包含每個呼叫的起始頂點 (From vertex) 和最後一個呼叫的結束頂點 (To vertex)。 - 如果找不到給定常數之間的呼叫鏈,則
of
運算子會回傳false
。 closure
運算子 (digraph
表示法) 的值由原子'closure()'
表示。- 一組帶行號的函數由已排序且不重複的
DefineAt
列表表示。 - 一組帶行號的函數呼叫由已排序且不重複的
CallAt
列表表示。 - 一組帶行號的函數和函數呼叫由已排序且不重複的
AllLines
列表表示。
對於 CallAt
和 AllLines
,對於任何列表元素,LineNumbers
都不是空列表;這些元素已被移除。 component
的常數和 LineNumbers
的整數都經過排序且不重複。
-spec remove_application(XrefServer, Applications) -> ok | {error, module(), Reason} when XrefServer :: xref(), Applications :: application() | [application()], Reason :: {no_such_application, application()}.
-spec replace_application(XrefServer, Application, Directory) -> {ok, Application} | {error, module(), Reason} when XrefServer :: xref(), Application :: application(), Directory :: directory(), Reason :: {no_such_application, Application} | add_dir_rsn().
等同於 replace_application(XrefServer, Application, Directory, [])
。
-spec replace_application(XrefServer, Application, Directory, Options) -> {ok, Application} | {error, module(), Reason} when XrefServer :: xref(), Application :: application(), Directory :: directory(), Options :: Option | [Option], Option :: {builtins, boolean()} | {verbose, boolean()} | {warnings, boolean()} | builtins | verbose | warnings, Reason :: {application_clash, {application(), directory(), directory()}} | {no_such_application, Application} | add_dir_rsn().
使用從應用程式目錄讀取的其他模組來取代應用程式的模組。
應用程式的釋出版本成員關係會保留。請注意,會保留應用程式的名稱;不會使用給定目錄的名稱。
-spec replace_module(XrefServer, Module, File, Options) -> {ok, Module} | {error, module(), Reason} when XrefServer :: xref(), Module :: module(), File :: file(), Options :: Option | [Option], Option :: {verbose, boolean()} | {warnings, boolean()} | verbose | warnings, Reason :: {module_mismatch, Module, ReadModule :: module()} | {no_such_module, Module} | add_mod_rsn().
使用從 BEAM 檔案讀取的資料來取代已分析的模組的模組資料。
模組的應用程式成員關係會保留,模組的 builtins
選項的值也會保留。如果讀取的模組名稱與給定模組不同,則會回傳錯誤。
update
函數是更新重新編譯模組模組資料的另一種選擇。
-spec set_default(XrefServer, OptionValues) -> ok | {error, module(), Reason} when XrefServer :: xref(), OptionValues :: OptionValue | [OptionValue], OptionValue :: {Option, Value}, Option :: builtins | recurse | verbose | warnings, Value :: boolean(), Reason :: {invalid_options, term()}.
為 OptionValues
給定的多個選項設定預設值。
關於選項的名稱及其允許的值,請參閱set_default/3
。
-spec set_default(XrefServer, Option, Value) -> {ok, OldValue} | {error, module(), Reason} when XrefServer :: xref(), Option :: builtins | recurse | verbose | warnings, Value :: boolean(), OldValue :: boolean(), Reason :: {invalid_options, term()}.
設定一個或多個選項的預設值。
可以透過這種方式設定的選項為
builtins
,初始預設值為false
;recurse
,初始預設值為false
;verbose
,初始預設值為false
;warnings
,初始預設值為true
。
建立 Xref 伺服器時會設定初始預設值。
-spec set_library_path(XrefServer, LibraryPath) -> ok | {error, module(), Reason} when XrefServer :: xref(), LibraryPath :: library_path(), Reason :: {file_error, file(), file_error()} | {invalid_options, term()} | {invalid_path, term()}.
-spec set_library_path(XrefServer, LibraryPath, Options) -> ok | {error, module(), Reason} when XrefServer :: xref(), LibraryPath :: library_path(), Options :: Option | [Option], Option :: {verbose, boolean()} | verbose, Reason :: {invalid_options, term()} | {invalid_path, term()}.
設定程式庫路徑。
如果給定的路徑是目錄列表,則會透過在給定的順序中走訪目錄時選擇遇到的第一個模組,來確定 函式庫模組 的集合,這些模組會出現在多個目錄中。預設情況下,函式庫路徑為空列表。
函式庫路徑 code_path
會被函數 m/1
和 d/1
使用,但也可以明確設定。不過請注意,在設定模組資料時,對於每個使用的 函式庫模組,程式碼路徑都會被走訪一次。另一方面,如果只有少數模組被使用但未被分析,則使用 code_path
可能比將函式庫路徑設定為 code:get_path/0
更快。
如果函式庫路徑設定為 code_path
,則不會確定函式庫模組的集合,而 info
函數會回傳空的函式庫模組列表。
-spec start(NameOrOptions) -> {ok, pid()} | {error, {already_started, pid()}} when NameOrOptions :: Name | Options, Name :: atom(), Options :: Option | [Option], Option :: {xref_mode, mode()} | term().
建立 Xref 伺服器。
此程序可以選擇性地指定一個名稱。預設的模式是 functions
。Xref 無法辨識的選項會傳遞給 gen_server:start/4
。
-spec start(Name, Options) -> {ok, pid()} | {error, {already_started, pid()}} when Name :: atom(), Options :: Option | [Option], Option :: {xref_mode, mode()} | term().
使用給定的名稱建立 Xref 伺服器。
預設的模式是 functions
。Xref 無法辨識的選項會傳遞給 gen_server:start/4
。
-spec stop(XrefServer) -> stopped when XrefServer :: xref().
停止 Xref 伺服器。
-spec update(XrefServer, Options) -> {ok, Modules} | {error, module(), Reason} when XrefServer :: xref(), Options :: Option | [Option], Option :: {verbose, boolean()} | {warnings, boolean()} | verbose | warnings, Modules :: [module()], Reason :: {module_mismatch, module(), ReadModule :: module()} | add_mod_rsn().
取代所有已分析的模組的模組資料,這些模組的 BEAM 檔案自上次由 add
函式或 update
讀取後已修改。
模組的應用程式成員關係會保留,builtins
選項的值也會保留。回傳被取代模組的名稱的已排序列表。
-spec variables(XrefServer, Options) -> {ok, [VariableInfo]} when XrefServer :: xref(), Options :: Option | [Option], Option :: predefined | user | {verbose, boolean()} | verbose, VariableInfo :: {predefined, [variable()]} | {user, [variable()]}.
傳回 Xref 伺服器的變數名稱排序清單。
預設為僅回傳使用者變數。