10.6 デッドコード候補の検知方法
デッドコード候補の検知方法について説明します。
デッドコードとは,プログラム実行時に実行される可能性がない文,プログラムなど,プログラムの実行結果に影響を与えないソースコードのことです。デッドコード候補から,テストが不要なプログラムの選定や,プログラムの処理の誤りを発見できます。
デッドコードの例を次の図に示します。
デッドコード検出の対象
COBOLソース解析では,登録集原文を取り込んだあとのCOBOLプログラム中のプログラム定義で,コンパイル対象になる行を検出対象とします。
デッドコード検出の対象でない項目
次に示すコードは検出対象外です。
-
利用者定義関数,クラス,インタフェース定義
-
コンパイル対象にならないデバッグ行,条件翻訳結果の無効行
-
Sレベル,Uレベルエラーが発生するCOBOLプログラム
-
覚え書きと見なされた文
デッドコード候補の種類
検出されるデッドコード候補の種類を次の表に示します。
項番 |
デッドコード候補の種類 |
内容 |
ソース表示(COPY展開後)時に背景をグレーにする行 |
---|---|---|---|
1 |
未使用の外部プログラム |
一度も呼び出されることがない外部プログラム |
PROGRAM-IDの行 |
2 |
未使用の内部プログラム |
一度も呼び出されることがない内部プログラム |
PROGRAM-IDの行 |
3 |
未使用のデータ項目 |
一度も参照されていないデータ項目 |
データ項目の定義位置 |
4 |
未使用のファイル名,報告書名,画面名,通信記述名 |
一度も参照されていないファイル名,報告書名,画面名,通信記述名 |
報告書名,画面名,通信記述名の定義位置 |
5 |
制御が渡らない文 |
実行時に制御が渡ることがない文 |
制御が渡ることがない文の先頭行から終了行 |
6 |
制御が渡らない手続き |
実行時に制御が渡ることがない手続き |
制御が渡ることがない手続きの定義位置 |
デッドコード候補の詳細
デッドコード候補として検出される内容を次に示します。
未使用の外部プログラム
解析対象の翻訳単位間で,どのプログラムからも呼び出されていないCOBOL主プログラム以外の外部プログラムが検出されます。COBOLソース解析では,次に示すプログラムを未使用の外部プログラムとします。
-
解析対象の翻訳単位間で,「CALL 定数」によって呼ばれることがない外部プログラム
-
「CALL 一意名」からだけ呼ばれている外部プログラムのうち,CALL 一意名に対応する呼び出し先プログラムとして解決できなかった外部プログラム
-
解析対象外の翻訳単位(他言語プログラムを含む)からだけ呼び出される外部プログラム
-
主プログラムでない,呼び出し元のCALL文がすべてデッドコード候補である外部プログラム
- (例)未使用の外部プログラムの例
-
次の例では,プログラムAにプログラムDを呼ぶCALL文が存在するが,CALL文がデッドコードであるためプログラムDもデッドコード候補として検出されます。また,プログラムDが呼ばれていないため,プログラムDからしか呼ばれていないプログラムEもデッドコード候補となります。プログラムFはプログラムCからの呼び出しがあるため,デッドコード候補にはなりません。
図10‒2 未使用の外部プログラムの例 - 注意
-
-
重複するプログラム名/ENTRY文で定義した入口点の名称が存在する場合で,かつそのプログラムを呼び出すCALL文があるときは,それらのプログラムはすべて呼ばれるものと仮定して処理されます。
-
未使用外部プログラムの場合,プログラム中のほかのデッドコードも検出します。
-
未使用の内部プログラム
最外プログラム中で,一度も呼び出されていない内部プログラムが検出されます。COBOLソース解析では,次に示すプログラムを未使用の内部プログラムとします。
-
プログラム内で,CALL/CANCEL文によって呼ばれることがない内部プログラム
-
呼び出し元のCALL/CANCEL文がすべてデッドコードである内部プログラム
プログラム中にCALL/CANCEL 一意名が存在する場合,COBOLソース解析では内部プログラムを次のように扱います。
-
CALL/CANCEL 一意名から呼ぶことができる内部プログラムは,使用される可能性がある内部プログラムとして扱われ,デッドコードではなくデッドコード候補として検出されます。
ただし,次の方法で,CALL 一意名に対応する呼び出し先プログラムとして解決された内部プログラムは,呼ばれるプログラムとして扱い,デッドコード候補から除きます。
-
[解析生成オプション設定]画面の[呼出先プログラム解決]タブに一意名呼び出し対応付けファイルを指定
なお,デッドコードの検出は,CALL 一意名に対応する呼び出し先プログラムが解決されたあとに実施します。ある内部プログラムがCALL 一意名の呼び出し先プログラムとして解決されていても,そのCALL 一意名がデッドコード(制御が渡らない文)で,呼び出し元のCALL/CANCEL 文がすべてデッドコードの場合,その内部プログラムは呼ばれるプログラムとは扱われないで,未使用の内部プログラムとして検出されます。
一意名呼び出し対応付けファイル(idcファイル)の作成方法については,「付録B.1 一意名呼び出し対応付けファイル」を参照してください。
-
未使用のデータ項目
データ部中の作業場所節,局所場所節,連絡節,画面節で定義している01,77,レベルのデータ項目定義で,プログラム中で1回も参照されていない項目が検出されます。COBOLソース解析では,定義したデータ項目が集団項目である場合,集団項目に属するすべてのデータ項目が未使用である場合だけ未使用のデータ項目として検出されます。また,デッドコード候補の処理からだけ参照されているデータ項目も,未使用のデータ項目として検出されます。
- 注意事項
-
-
COBOLソース解析では,ファイル節で定義しているレコード記述項および報告書節で定義している報告集団記述項が未使用かどうかは検出されません。これらが未使用かどうかは,未使用のファイル名,報告書名の検出結果で判断してください。
-
埋め込みSQL宣言節内で定義しているデータ項目がSQL文中で使用されていても,COBOLの構文中で使用されていない場合は,未使用のデータ項目として検出します。このため,埋め込みSQL宣言節内のデータ項目が未使用のデータ項目として検出された場合は,SQL文中でも使用されていないかどうかを確認してください。
-
データ項目が参照された場合,そのデータ項目の定義に必要なデータ項目は未使用のデータ項目として検出されません。
-
- (例)
-
未使用のデータ項目として検出されない例
01 A PIC X. 01 B REDEFINES A PIC 9.
上記の定義に対し,データ項目「B」が参照されている場合,データ項目「A」は未使用のデータ項目として検出されません。
未使用のファイル名,報告書名,画面名,通信記述名
ファイル名,報告書名,画面名,通信記述名の中で,手続き部から1回も参照されていないものが検出されます。
ファイル名,報告書名,画面名が参照された場合,各項目の定義に必要なデータ項目は未使用のデータ項目として検出されません。
- (例)
-
未使用のデータ項目として検出されない例
FILE-CONTROL. SELECT FILE1 ASSIGN TO 'FNAME' FILE STATUS FS1. : WORKING-STORAGE SECTION. 01 FS1 PIC X(2).
上記の定義に対し,ファイル「FILE1」が参照されている場合,データ項目「FS1」は未使用のデータ項目として検出されません。
制御が渡らない文,手続き
実行時に制御が渡る可能性がない文,手続きが検出されます。COBOLソース解析では,次の文および手続きを制御が渡らない文と判断します。
-
GO TO文,GOBACK文など,次の文に実行の制御を移さない文があるとき,その文の後ろに続く文から,その文が属する節,段落,無条件文の終わり,またはENTRY文の前まで。
-
GO TO文やPERFORM文による参照がなく,先行する節,段落からも制御が渡ることがない手続き。
ただし,次に示す文および手続きは,実行時に制御が渡る可能性がある文および手続きと判断します。
-
宣言部分のUSE手続き
-
非宣言部分の最初の文
-
ENTRY文
- (例)
-
実行時に制御が渡る可能性がある文および手続きと判断する例
PROCEDURE DIVISION. DECLARATIVES. USE-PROC SECTION. *> 宣言部分のUSE手続きは制御が USE AFTER EXCEPTION CONDITION *> 渡る可能性があると判断する EC-SIZE-ZERO-DIVIDE. DISPLAY 'ゼロ除算発生'. RESUME 復帰手続き. DISPLAY 'DEAD CODE'. *> デッドコード候補 END DECLARATIVES. PROC-SEC SECTION. ACCEPT X. *> 非宣言部分の最初の文は制御が *> 渡る可能性があると判断する >>TURN EC-SIZE CHECKING ON DIVIDE 10 BY X GIVING RESULT. DISPLAY RESULT. STOP RUN. DISPLAY 'DEAD CODE'. *> デッドコード候補 ENTRY 'ENTRY1'. *> ENTRY文は制御が渡る可能性が DISPLAY '入口点:ENTRY1'. *> あると判断する :
- 次の文に実行の制御を移さない文
-
次の文に実行の制御を移さない文を次に示します。
-
画面機能のACCEPT文/ REPLY文(USE FOR WINDOW節内)
-
EXIT PERFORM文
-
EXIT USE文
-
GO TO文
-
GOBACK文
-
IF文/SEARCH文のNEXT SENTENCE
-
RESUME文
-
STOP文
-
手続き先から制御が戻って来ないそとPERFORM文,PROCEDURE指定のあるSORT/MERGE文(USE手続き中に「RESUME 手続き名」が存在する場合を除く)
- (例)
-
PERFORM文の例
A. PERFORM B. DISPLAY 'A'. *> デッドコード候補 B. STOP RUN.
- USE手続き中に「RESUME 手続き名」が存在する場合
-
「RESUME 手続き名」が存在する場合,そとPERFORM文とPROCEDURE指定のがあるSORT/MERGE文は,指定された手続き先から必ず制御が戻ってくるものとして扱います。
次に示すプログラムでは,1.のPERFORM文を実行すると手続きA中で4. STOP RUN文を実行するため,PERFORM文に制御が戻ってきません。このため,2.のDISPLAY文は実行されません(デッドコード候補)。しかし,手続きA中の3.で例外が発生すると,USE手続きを通して手続きBへ制御が渡ることがあります。この場合,1.のPERFORM文に制御が戻り,2.のDISPLAY文も実行されます。
COBOLソース解析,PERFORM/SORT/MERGE文に指定した手続き先で,実行時に例外が発生するかどうかは判断しません。このため,手続き先での例外の発生を考慮し,「RESUME 手続き名」が存在するプログラムの場合,PERFORM/SORT/MERGE文に指定された手続き先からは,必ず制御が戻ると仮定します。
このプログラムの例では,1.のPERFORM文は必ず制御が戻ると仮定するため,2.のDISPLAY文はデッドコード候補として検出されません。
(例)
PERFORM文の例
USE-PROC SECTION. USE AFTER EXCEPTION CONDITION EC-ALL. RESUME B. END DECLARATIVES. ST. ACCEPT X. MOVE 123 TO Y. PERFORM A THRU B. *> 1. DISPLAY 'AFTER PERFORM'. *> 2. デッドコード候補ではないと仮定 STOP RUN. A. DISPLAY 'A'. COMPUTE X = Y / X. *> 3. STOP RUN. *> 4. B. DISPLAY 'B'.
-
条件文(IF,EVALUATE)や条件指定([NOT] ON SIZE ERRORなど)のある文で,すべての分岐先の無条件文に制御を移す文が存在
- (例)
-
すべての分岐先の無条件文に制御を移す文が存在する例
A. IF X = 1 THEN GO TO B ELSE GO TO C END-IF. DISPLAY 'A'. *> デッドコード候補 B. C.
-
- 注意
-
-
条件文,または条件指定付きの文がある場合,すべての分岐先が実行される可能性があると仮定されます。
ALTER文で飛び先が変更されているGO TO文がある場合,そのGO TO文を参照しているすべてのALTER文に指定された飛び先の手続きは,実行されると仮定されます。
(例) 次に示す例では,手続きA中のGO TO文は,ALTER文によって飛び先を手続きXまたはYに変更しています。このプログラムで手続きA中のGO TO文に制御が渡る場合,手続きX,手続きYの両方とも実行される手続きと仮定されます。
ALTER A TO X. : ALTER A TO Y. : A. GO TO. B. STOP RUN. : X. *> 実行される可能性があると仮定する : Y. *> 実行される可能性があると仮定する :
-
- (例1)制御が渡らない文の例1
-
次のプログラムでは,GOBACK文の後ろにある文は実行されることがないため,デッドコード候補として検出されます。
A. GOBACK. DISPLAY 'this is dead code'. *> デッドコード候補
- (例2)制御が渡らない文の例2
-
次のプログラムでは,手続きBの最初の文であるDISPLAY文に制御が渡ることはないが,ENTRY文は実行される可能性があると判断されます。このため,手続きBの最初のDISPLAY文だけデッドコード候補として検出されます。
PROCEDURE DIVISION. A. DISPLAY 'XXX'. STOP RUN. B. DISPLAY 'this is dead code'. *> デッドコード候補 ENTRY 'YYY'. DISPLAY 'YYY'.
- (例3)制御が渡らない手続きの例
-
次のプログラムでは,IF文のTHEN節,ELSE節は両方実行される可能性があると判断されます。その結果,手続きBをデッドコード候補として検出されます。
: PROCEDURE DIVISION. A. ACCEPT X. IF X = 1 THEN PERFORM C ELSE GO TO D END-IF. STOP RUN. B. *> デッドコード候補の手続き GO TO D. C. D.
デッドコード候補の検知の注意
-
COBOLソース解析では,登録集原文取り込み後のCOBOLプログラムをデッドコード候補の検出対象とするため,登録集原文中の行に対してデッドコード候補が検出されることがあります。しかし,そのデッドコード候補となった登録集原文中の行は,ほかのCOBOLプログラムではデッドコード候補にならないことがあります。デッドコード候補の個所を修正するときは,呼び出し関連を確認してください。
-
デッドコード候補の検知以外のコンパイルエラーが出力されるのを防ぐため,解析するCOBOLプログラムに必要なすべてのコンパイラオプションとコンパイラ環境変数を指定してください。
-
デッドコード(制御が渡らない手続き)として検出された節や段落は,[ソース表示(COPY展開後)]画面で節見出しや段落見出しの部分だけが網掛けされます。節がデッドコード(制御が渡らない手続き)の場合,その節に属するすべての段落もデッドコード(制御が渡らない手続き)ですが,段落見出しは網掛けされません。節見出しが網掛けされている場合は,節全体(節に属する段落すべてを含む)がデッドコードであると解釈してください。
-
ENTRY文はCOBOLソース解析では解析対象外です。このため,ENTRY文の入口名で呼び出されていても,プログラム名で呼び出されていないプログラムは「未使用」として表示されます。