以下、本実施の形態について図面を参照して説明する。
[第1の実施の形態]
図1は、第1の実施の形態の情報処理装置を示す図である。情報処理装置1は、コンパイラとして機能し、ソースコードのコンパイルに用いられる。情報処理装置1は、表示装置2に接続されている。表示装置2は、情報処理装置1により出力される情報の表示に用いられる。情報処理装置1は、記憶部1aおよび処理部1bを有する。
記憶部1aは、RAM(Random Access Memory)などの揮発性記憶装置でもよいし、HDD(Hard Disk Drive)やフラッシュメモリなどの不揮発性記憶装置でもよい。処理部1bは、CPU(Central Processing Unit)、DSP(Digital Signal Processor)、ASIC(Application Specific Integrated Circuit)、FPGA(Field Programmable Gate Array)などを含み得る。処理部1bはプログラムを実行するプロセッサであってもよい。ここでいう「プロセッサ」には、複数のプロセッサの集合(マルチプロセッサ)も含まれ得る。
記憶部1aは、ソースコード3を記憶する。ソースコード3は、ユーザによって作成される。ソースコード3は、ソースプログラムと呼ばれてもよい。例えば、ソースコード3は、C++やJAVA(登録商標)などの高級言語を用いて記述される。ソースコード3は、複数のシンボルを含む。シンボルは、変数、関数、クラスおよび構造体などのソースコード3に含まれるプログラムの要素を表す識別名である。
処理部1bは、記憶部1aに記憶されたソースコード3に含まれるシンボルに対し、当該シンボルの仕様が非推奨であることの警告の出力に用いられる属性情報を追加する。シンボルの仕様が非推奨であることの警告の出力は、ソースコード3をコンパイルするコンパイラによる出力である。
処理部1bは、記憶部1aに記憶されたコンパイラプログラムを実行することで、コンパイラの機能を発揮してもよい。あるいは、コンパイラの機能は、情報処理装置1が有する所定の演算装置により発揮されてもよい。属性情報は、メタデータ、タグまたはアノテーションなどと呼ばれてもよい。コンパイラは、オブジェクトコードの生成過程において、変数と変数を参照する関数やクラスなどとの関係、および、宣言または定義された関数やクラスなどが実際に実行されるか否かを判断し、属性情報に応じた非推奨警告を出力する機能を予め備えるものがある。このような属性情報として、例えば、C++やJAVAなどのコンパイラで利用されるdeprecated属性が挙げられる。
deprecated属性は、既に存在している機能に不具合が見つかった場合や、より良い新機能が登場した際に過去の機能を非推奨にするために利用される。一例として、C++では、deprecated属性を、クラスの型、型の別名、変数、非静的メンバ変数、関数および列挙型に対して指定することができる。具体的には、ソースコード3におけるシンボルの宣言または定義の記述箇所に対する所定位置(例えば、シンボルの直前など)に、deprecatedの文字列を含む所定のコードを挿入することで、当該シンボルにdeprecated属性を付与できる。例えば、コンパイラは、“deprecated属性”が付与されたシンボルが使用されると、該当のシンボルが非推奨の機能であることを警告したり、代替となる機能を提示したりする。
1つの例として、図1では、属性情報に相当する文字列を“attribute”と表記する。例えば、ソースコード3は、整数型(int型)の変数“x”、および、関数“func01()”を含む。変数“x”は、ソースコード3に含まれる複数のシンボルのうちの1つのシンボルである。また、関数“func01”は、ソースコード3に含まれる複数のシンボルのうちの1つのシンボルである。例えば、処理部1bは、ソースコード3に含まれるシンボル“x”の定義“int x;”の直前に、属性情報に相当するコード“<attribute>”を追加する。同様に、処理部1bは、ソースコード3に含まれるシンボル“func01”の定義“func01(){・・・}”の直前に、属性情報に相当するコード“<attribute>”を追加する。ここで、図1で例示するプログラム言語は、属性情報を記号“<”、“>”で括る規約をもつものとする。ソースコード4は、ソースコード3の各シンボルに属性情報が追加された結果である。
ただし、処理部1bは、ソースコード3に対して所定の構文解析(オブジェクトコード作成の前段階の処理)を行った結果として得られる所定の中間情報に、属性情報を追加してもよい。
処理部1bは、ソースコード4のコンパイルの際にシンボルに対して、コンパイラにより属性情報に応じた警告が出力されたか否かを判定する。処理部1bは、あるシンボルに対して警告が出力されていない場合、当該シンボルを、ソースコード4(またはソースコード3)に記述された処理において使用されない未使用シンボルであると決定する。「未使用シンボル」の一例としては、宣言または定義はされているものの、該当のソースコードに対応するオブジェクトコードにより実行される関数やクラスなどで参照されない変数や、宣言や定義だけあって実行されない関数やクラスなどが考えられる。
例えば、処理部1bは、属性情報に応じたコンパイラによる警告として、出力5を得たとする。出力5は、シンボル“func01()”が非推奨であることの警告を含むが、シンボル“int x”が非推奨であることの警告を含まない。このため、処理部1bは、シンボル“func01()”がソースコード4に記述された処理において使用されるシンボルであると判定する。一方、処理部1bは、シンボル“x”がソースコード4に記述された処理において使用されない未使用シンボルであると決定する。
なお、出力5は、処理部1bにより付与された属性情報に応じた警告であるため、記憶部1aに出力5の情報がログなどに記録されればよく、表示装置2により出力5の内容は表示されなくてもよい。ここで、本例では、シンボル“func01()”が「真に」非推奨であるか否かについては不問としてよい。寧ろ、処理部1bは、コンパイラによる属性情報に応じた機能を、本来の機能とは別の用途(すなわち、未使用シンボルの特定)に流用するために、各シンボルに対して属性情報を付加するので、シンボル“func01()”は非推奨ではないこともある。ただし、コンパイラが属性情報に応じた本来の機能(非推奨機能に対する警告)を果たすために、ユーザが追加した属性情報と、処理部1bが追加した属性情報とを区別することも考えられる。
具体的には、処理部1bは、ユーザの操作により付加された第1のタイプの属性情報(本来の非推奨警告の通知のためのもの)と、処理部1bにより不使用シンボルの特定のために付加された第2のタイプの属性情報とを区別してもよい。例えば、処理部1bは、ソースコード3に予め記述されていた属性情報を第1のタイプとし、コンパイル時に処理部1bが追加した属性情報を第2のタイプとして区別する。そして、処理部1bは、出力5に含まれるシンボルに関する警告が、第1のタイプおよび第2のタイプの何れの属性情報に応じたものであるかにより、コンパイラによる非推奨警告の表示装置2による表示内容を制御してもよい。すなわち、処理部1bは、第1のタイプの場合は非推奨警告を表示させ、第2のタイプの場合は非推奨警告を表示させないように制御してもよい。
処理部1bは、未使用シンボルの情報を出力する。例えば、処理部1bは、未使用シンボルの宣言または定義に相当するソースコード4の中のコードを、表示装置2に出力し、当該コードを表示装置2により表示させてもよい。より具体的には、処理部1bは、“warning: ‘int x’ is unused.”のように、シンボル“int x”が未使用であることを示すメッセージを含む出力6の内容を、表示装置2により表示させてもよい。
次に、情報処理装置1による処理手順を説明する。
図2は、第1の実施の形態の処理例を示すフローチャートである。以下、図2に示す処理をステップ番号に沿って説明する。
(S1)処理部1bは、ソースコード3のコンパイルの指示を受け付けると、ソースコード3の各シンボルに対して属性情報を追加する。
(S2)処理部1bは、コンパイラの機能により、ソースコード4(または、ソースコード4に相当する中間情報)に対応するオブジェクトコードを生成する。
(S3)処理部1bは、ソースコード4(または、ソースコード3)に含まれるシンボルを1つ選択する。選択対象となるシンボルは、今回の処理で未選択であるシンボルである。
(S4)処理部1bは、ステップS1で追加した属性情報に応じたコンパイラによる警告の出力(非推奨警告の出力)があるか否かを判定する。ある場合、処理部1bは、ステップS5に処理を進める。ない場合、処理部1bは、ステップS6に処理を進める。
(S5)処理部1bは、該当のシンボルが使用されていると決定する。そして、処理部1bは、ステップS7に処理を進める。
(S6)処理部1bは、該当のシンボルが未使用であると決定する。そして、処理部1bは、ステップS7に処理を進める。
(S7)処理部1bは、ステップS1で属性情報を追加した全てのシンボルを選択済であるか(ステップS3の選択を行ったか)否かを判定する。属性情報を追加した全てのシンボルを選択済である場合、処理部1bは、ステップS8に処理を進める。属性情報を追加した全てのシンボルを選択済でない場合、処理部1bは、ステップS3に処理を進める。
(S8)処理部1bは、未使用シンボルの情報を出力する。例えば、処理部1bは、出力6の内容を表示装置2に表示させる。
このように、処理部1bは、コンパイラによる非推奨警告の出力に用いられる属性情報を各シンボルに付加することで、コンパイラによる各シンボルに対する非推奨警告の有無により、各シンボルが使用されているか、使用されていないかを識別する。
こうして、コンパイラに予め備わっている機能を流用することで、未使用シンボルの抽出機能の実装を容易にすることができる。また、処理部1bは、未使用シンボルの情報を出力することで、ユーザ(ソフトウェアの開発者)による未使用シンボルの発見およびソースコード3の改善を支援できる。
また、処理部1bは、コンパイラによる非推奨警告の出力処理の結果を用いて、未使用シンボルの抽出処理を行うので、未使用シンボルの抽出処理を別個のルーチンによって実行しなくてよい。具体的には、コンパイル処理とは別個に、各シンボルが使用されているか否かのチェック処理を行わずに済む。このため、未使用シンボルの抽出処理の効率化を図ることができる。また、未使用シンボルを抽出するためのルーチンを別個に行うよりも、処理部1bは、未使用シンボルの抽出を高速化できる。
更に、処理部1bは、ソースコード3を再度コンパイルする際に、未使用シンボルの情報に基づいて、ソースコード3に含まれる未使用シンボルをコンパイルの対象外とすることも可能である。
なお、ソースコード3は、複数のソースファイルに分割して作成されることもある。例えば、各ソースファイルは、別個のユーザ、別個の場所、および、別個の時間に作成され、それぞれ別個にコンパイルされ得る。この場合、情報処理装置1は、各ソースファイルに対して個別に作成された各オブジェクトファイルを結びつける(リンクする)ことで、実行ファイルを生成することになる。
情報処理装置1は、このようにソースコード3が複数のソースファイルに分割して作成される場合でも、ソースコード3の全体にわたって、未使用シンボルを抽出する機能を提供することができる。具体的には次の通りである。なお、以下では、プログラミング言語の一例としてC++を挙げる(ただし、他のプログラミング言語でもよい)。
図3は、第1の実施の形態のソースコードの例(その1)を示す図である。ソースコード30は、ソースファイル31,32に分割して作成される。ソースファイル31,32は、個別のファイルとして管理される。ソースファイル31のファイル名は、“sample.cpp”である。ソースファイル32のファイル名は、“main.cpp”である。
処理部1bは、ソースファイル31,32を個別にコンパイルする。このとき、処理部1bは、ソースファイル31,32それぞれに含まれる各シンボルに対して、C++の規約に則って、deprecated属性を付加する。
図4は、第1の実施の形態のソースコードの例(その2)を示す図である。ソースコード40は、ソースコード30に含まれるソースファイル31,32の各シンボルに対して、deprecated属性を付加した結果である。ソースコード40は、ソースファイル41,42を含む。ソースファイル41は、ソースファイル31の各シンボルに対してdeprecated属性を付加した結果である。ソースファイル42は、ソースファイル32の各シンボルに対してdeprecated属性を付加した結果である。この場合、属性情報は、2重の角括弧記号“[[”、“]]”で囲われた“[[deprecated]]”のコード部分に相当する。前述のように、deprecated属性の付加対象のシンボルおよびdeprecated属性の付加方法は、C++の規約に従って決定される。
なお、図4では、ソースファイル41,42それぞれにdeprecated属性を追加する例を示しているが、前述のように、ソースファイル41,42それぞれに対応する所定の中間情報を、deprecated属性を付加した状態で作成してもよい。
図5は、第1の実施の形態の未使用シンボルの他の出力例を示す図である。処理部1bは、ソースファイル31に対して図2の手順を実行することで、ソースファイル31に対するリストL1を作成する。リストL1は、ソースファイル31に関する未使用シンボルの情報の出力結果である。処理部1bは、ソースファイル31(またはソースファイル41)に対応するオブジェクトファイル7に、リストL1を追加する。処理部1bは、作成されたオブジェクトファイル7を記憶部1aに格納する。オブジェクトファイル7のファイル名は、例えば“sample.o”である。
ここで、リストL1は、ソースファイル31に含まれるシンボルに対応する要素名と、使用フラグとの対応関係を示す情報である。使用フラグとは、図2の手順により、該当のシンボルが「使用されている」と判定されたか、または、「未使用である」と判定されたかを示すフラグである。例えば、使用フラグ“TRUE”は、「使用されている」ことを示す。使用フラグ“FALSE”は、「未使用である」ことを示す。
同様に、処理部1bは、ソースファイル32に対して図2の手順を実行することで、ソースファイル32に対するリストL2を作成する。リストL2は、ソースファイル32に関する未使用シンボルの情報の出力結果である。処理部1bは、ソースファイル32(またはソースファイル42)に対応するオブジェクトファイル8に、リストL2を追加する。処理部1bは、作成されたオブジェクトファイル8を記憶部1aに格納する。オブジェクトファイル8のファイル名は、例えば“main.o”である。なお、リストL2も、リストL1と同様に、ソースファイル32に含まれるシンボルに対応する要素名と使用フラグとの対応関係を示す情報である。
そして、処理部1bは、リンカの機能により、オブジェクトファイル7およびオブジェクトファイル8に対するリンク処理を行い、実行ファイル9(a.out)を作成する。このとき、処理部1bは、オブジェクトファイル7に含まれるリストL1およびオブジェクトファイル8に含まれるリストL2をマージすることで、マージ後のリストL3を作成し、リストL3に基づいて、未使用シンボルを抽出する。
特に、処理部1bは、リンク処理において、リンク時最適化(LTO:Link Time Optimization)と呼ばれる最適化を行う。リンク時最適化では、個々のオブジェクトファイルの最適化だけでなく、オブジェクトファイル間の最適化(例えば、オブジェクトファイルを跨いだプログラム全体に渡る関数のインライン化や定数伝播など)を可能とする。なお、LTOを用いる場合、コンパイル時に、所定の中間表現(例えば、Gimpleデータ)をオブジェクトファイル中に残すようコンパイルオプションが選択される。処理部1bによるリストL3の作成および未使用シンボルの抽出は、例えば、LTO実行時に行われてもよい。
例えば、処理部1bは、リストL1,L2の少なくとも一方に含まれる要素名を、リストL3の要素名の項目に登録する。また、処理部1bは、リストL3に登録した要素名に対して、リストL1,L2それぞれの使用フラグを参照し、少なくとも一方の使用フラグが“TRUE”であれば、リストL3の当該要素名に対する使用フラグを“TRUE”とする。両方の使用フラグが“FALSE”であれば、処理部1bは、リストL3の当該要素名に対する使用フラグを“FALSE”とする。
そして、処理部1bは、リストL3で使用フラグが“FALSE”である要素名に対するシンボルを、ソースコード30に記述された処理(すなわち、実行ファイル9により実行される処理)で使用されていない未使用シンボルであると決定する。
こうして、処理部1bは、リストL2,L3に基づいて、リンク対象の各オブジェクトファイルの少なくとも何れかで使用されているシンボルについては使用されていると判断する。一方、処理部1bは、リンク対象の何れのオブジェクトファイルでも使用されていないシンボルを未使用シンボルと判断する。
例えば、図5の例の場合、処理部1bは、リストL3に基づいて変数“global_y”、関数“func01(void)”、および、変数“x”を未使用シンボルと判定する。したがって、例えば、処理部1bは、これら未使用シンボルに関する記述“int global_y”、“void func01(void)”、および“int x”が未使用(Unused)であることを出力し、表示装置2に表示させる。出力6aは、未使用であることの警告の一例である。例えば、処理部1bは、出力6aの内容を表示装置2に表示させてもよい。
このように、分割コンパイルが行われる場合にも、処理部1bは、オブジェクトファイル7にリストL1を追加し、オブジェクトファイル8にリストL2を追加することで、リンク処理時(LTO時)に、リストL1,L2を基に未使用シンボルを抽出可能となる。また、こうして抽出した未使用シンボルの情報を出力することで、ユーザ(ソフトウェアの開発者)による未使用シンボルの発見およびソースコード30の改善を支援できる。また、処理部1bは、ソースファイル31,32それぞれを再度コンパイルする際に、未使用シンボルの情報に基づいて、ソースファイル31,32に含まれる未使用シンボルをコンパイルの対象外とすることも可能である。
以下では、情報処理装置1の一例として、ソースコードのコンパイルおよびリンク処理を行うコンピュータ(コンパイラ装置と称する)を例示し、情報処理装置1の機能を更に具体的に説明する。
[第2の実施の形態]
図6は、第2の実施の形態のコンパイラ装置のハードウェア例を示す図である。コンパイラ装置100は、プログラミング言語C++のコンパイラとして機能する。
ここで、C++では、2014年にISO(International Organization for Standardization)/IEC(International Electrotechnical Commission)14882:2014(通称C++14)という規格が策定されている。C++14では、新機能の1つに[[deprecated]]属性(単に、deprecated属性と称することがある)と呼ばれる機能が追加されている。本属性が指定されたオブジェクトが使用されると、コンパイラは警告メッセージを出力する。前述のように、deprecated属性は、既に存在している機能に不具合が見つかった場合や、より良い新機能が登場した際に過去の機能を非推奨にするために利用される機能である。
ただし、コンパイラは、deprecated属性による非推奨警告の出力機能をもつものであれば、C++の他のバージョン、および、他のプログラミング言語(例えば、JAVAなど)でもよい。
コンパイラ装置100は、プロセッサ101、RAM102、HDD103、画像信号処理部104、入力信号処理部105、媒体リーダ106および通信インタフェース107を有する。各ハードウェアはコンパイラ装置100のバスに接続されている。
プロセッサ101は、コンパイラ装置100の情報処理を制御するハードウェアである。プロセッサ101は、マルチプロセッサであってもよい。プロセッサ101は、例えばCPU、DSP、ASICまたはFPGAなどである。プロセッサ101は、CPU、DSP、ASIC、FPGAなどのうちの2以上の要素の組み合わせであってもよい。
RAM102は、コンパイラ装置100の主記憶装置である。RAM102は、プロセッサ101に実行させるOS(Operating System)のプログラムやアプリケーションプログラムの少なくとも一部を一時的に記憶する。また、RAM102は、プロセッサ101による処理に用いる各種データを記憶する。
HDD103は、コンパイラ装置100の補助記憶装置である。HDD103は、内蔵した磁気ディスクに対して、磁気的にデータの書き込みおよび読み出しを行う。HDD103は、OSのプログラム、アプリケーションプログラム、および各種データを記憶する。コンパイラ装置100は、フラッシュメモリやSSD(Solid State Drive)などの他の種類の補助記憶装置を備えてもよく、複数の補助記憶装置を備えてもよい。
画像信号処理部104は、プロセッサ101からの命令に従って、コンパイラ装置100に接続されたディスプレイ11に画像を出力する。ディスプレイ11として、CRT(Cathode Ray Tube)ディスプレイや液晶ディスプレイなどを用いることができる。
入力信号処理部105は、コンパイラ装置100に接続された入力デバイス12から入力信号を取得し、プロセッサ101に出力する。入力デバイス12として、例えば、マウスやタッチパネルなどのポインティングデバイス、キーボードなどを用いることができる。
媒体リーダ106は、記録媒体13に記録されたプログラムやデータを読み取る装置である。記録媒体13として、例えば、フレキシブルディスク(FD:Flexible Disk)やHDDなどの磁気ディスク、CD(Compact Disc)やDVD(Digital Versatile Disc)などの光ディスク、光磁気ディスク(MO:Magneto-Optical disk)を使用できる。また、記録媒体13として、例えば、フラッシュメモリカードなどの不揮発性の半導体メモリを使用することもできる。媒体リーダ106は、例えば、プロセッサ101からの命令に従って、記録媒体13から読み取ったプログラムやデータをRAM102またはHDD103に格納する。
通信インタフェース107は、ネットワーク10を介して他の装置と通信を行う。通信インタフェース107は、有線通信インタフェースでもよいし、無線通信インタフェースでもよい。
図7は、deprecated属性付与後のソースコードの例を示す図である。ソースコードP1は、C++を用いて記述されたソースコードの一例である。ソースコードP1のファイル名を“main.cpp”とする。前述のように、C++では、2重の角括弧記号“[[”、“]]”で囲われた“[[deprecated]]”というコードをシンボルに付与することで、非推奨警告のための属性情報が追加される。また、“deprecated”に続けて括弧記号“(”、“)”を記述し、当該括弧記号で括られた2重引用符により、ユーザが警告として表示させたいメッセージを設定することもできる。ユーザが表示させたいメッセージを設定しない場合は、2重引用符の中に何も記述しないか、または、“deprecated”の文字列に続く括弧記号および2重引用符を記述しないこともある。
具体的には、ソースコードP1の1行目は、構造体を表すシンボル“X{}”にdeprecated属性が付与された例である。[[deprecated(“warning”)]]は、非推奨警告のための属性情報である。当該属性情報のオプションとして含まれる“warning”の文字列は、コンパイラが出力する規定の警告とは別に、ユーザが表示させたいメッセージである。
また、ソースコードP1の3行目は、列挙型(列挙体と呼ばれることもある)を表すシンボル“{ZERO,ONE}”にdeprecated属性が付与された例である。[[deprecated(“”)]]は、非推奨警告のための属性情報である。当該2行目の例では、ユーザが表示させたいメッセージの設定はないことになる。
ソースコードP1には、他のシンボルに対しても、C++の規約に則って、deprecated属性が付与されている。また、main関数およびmain関数の定義ブロック(9行目〜20行目)はdeprecated属性の付与対象外となる。
図8は、非推奨の警告メッセージの出力例を示す図である。メッセージ群11aは、コンパイラ装置100によりソースコードP1のコンパイルが行われた場合に、ディスプレイ11により表示される非推奨であることの警告メッセージ(すなわち、コンパイラ装置100による非推奨警告の出力の内容)の例である。なお、メッセージ群11aは、GCC(GNU Compiler Collection)6.1.0を用いて出力したものである。
具体的には、メッセージ群11aは、ソースコードP1のmain関数において使用される構造体“X”が非推奨である旨の警告メッセージ(メッセージ群11aの3行目〜9行目)を含む。また、メッセージ群11aは、ソースコードP1のmain関数において使用される変数“x”が非推奨である旨の警告メッセージ(メッセージ群11aの10行目〜16行目)を含む。また、メッセージ群11aは、ソースコードP1のmain関数において使用される関数“func()”が非推奨である旨の警告メッセージ(メッセージ群11aの17行目〜30行目)を含む。
なお、メッセージ群11aは、ソースコードP1における列挙型のシンボルに対する非推奨である旨の警告メッセージを含まない。該当の列挙型は、main関数において使用されていないからである。
このように、コンパイラ装置100は、deprecated属性の機能を用いることで、ソースコードP1内で使用されるシンボルに対して非推奨である旨の警告メッセージをコンパイラにより出力させることができる。ここで、「使用されるシンボル」とは、ソースコードP1に対応するオブジェクトコードにより実現される処理(すなわち、ソースコードP1に記述された処理)で使用されるシンボルである。「使用されないシンボル」とは、ソースコードP1に対応するオブジェクトコードにより実現される処理(すなわち、ソースコードP1に記述された処理)で使用されないシンボルである。そこで、コンパイラ装置100は、コンパイラによる非推奨警告の出力機能を活用して、不使用シンボルの抽出を行う。具体的には次の通りである。
図9は、コンパイラ装置の機能例を示す図である。コンパイラ装置100は、ソースファイル記憶部110、中間コード記憶部120、オブジェクトファイル記憶部130、実行ファイル記憶部140、字句解析部151、構文解析部152、意味解析部153、属性追加部161、警告出力部162、最適化部171、出力生成部172、LTO処理部181、リスト結合部182および結果出力部183を有する。
ソースファイル記憶部110は、複数のソースファイルを記憶する。例えば、ソースファイル記憶部110は、ソースファイル111,112を記憶する。ソースファイル111,112は、ある実行ファイルの作成に用いられる。ソースファイル111,112は、別個のファイルとして管理されるが、当該実行ファイルに対応する1つのソースコードを形成するものと捉えられる。
中間コード記憶部120は、ソースファイル111,112それぞれに対応する中間コードを記憶する。中間コードは、オブジェクトコードの前段階のコードである。
オブジェクトファイル記憶部130は、複数のオブジェクトファイルを記憶する。例えば、オブジェクトファイル記憶部130は、オブジェクトファイル131,132を記憶する。オブジェクトファイル131は、ソースファイル111に基づいて生成されたオブジェクトファイルである。オブジェクトファイル132は、ソースファイル112に基づいて生成されたオブジェクトファイルである。
実行ファイル記憶部140は、オブジェクトファイル131,132に対するリンク処理の結果として生成された実行ファイルを記憶する。
字句解析部151は、ソースファイル111,112に対する字句解析処理を行う。具体的には、字句解析部151は、ソースファイル111に記述された文字(字)を特定し、文字の並びから文字列(句)を特定する。字句解析部151は、ソースファイル112に対しても同様に字句解析処理を行う。
構文解析部152は、ソースファイル111,112に対する構文解析処理を行う。具体的には、構文解析部152は、字句解析部151により特定された字句の組み合わせ(構文)を特定し、構文木の情報を生成する。構文木の情報は、オブジェクトコードの作成の前段階に作成される中間情報であるといえる。
意味解析部153は、ソースファイル111,112に対する意味解析処理を行う。具体的には、意味解析部153は、構文解析部152により特定された構文から、プログラム言語で規定されている命令や記法を抽出し、最適化処理に用いられる中間コードを生成する。意味解析部153は、生成された中間コードを中間コード記憶部120に格納する。このとき、意味解析部153は、変数、関数およびクラスなどの宣言または定義や、それらの呼び出し関係などを特定する。また、意味解析部153は、各シンボルについて、後述する属性追加部161によって追加されるdeprecated属性の有無も解析し、使用されるシンボルに対する非推奨警告の出力を、警告出力部162に指示する。
属性追加部161は、C++の規約に則って、ソースファイル111から作成された構文木に含まれるシンボルにdeprecated属性を追加する。同様に、属性追加部161は、ソースファイル112から作成された構文木に含まれるシンボルにdeprecated属性を追加する。意味解析部153は、追加されたdeprecated属性も含めて、意味解析処理を行うことになる。
警告出力部162は、意味解析部153の指示により、deprecated属性に応じた非推奨警告をディスプレイ11に表示させる。具体的には、警告出力部162は、ソースファイル111,112に対してユーザによりdeprecated属性が追加されたシンボルに絞って、非推奨警告をディスプレイ11に表示させる。例えば、警告出力部162は、該当のシンボルに対応する機能の使用が非推奨である旨の警告メッセージをディスプレイ11により表示させる。一方、警告出力部162は、属性追加部161によりdeprecated属性が追加されたシンボルに対して、非推奨警告の出力を行わない。また、警告出力部162は、各シンボルに対する非推奨警告の有無を記録したリストを作成し、出力生成部172に提供する。
ここで、リストは、要素名、使用フラグおよびユーザ定義パラメータを対応付けた情報である。要素名、使用フラグおよびユーザ定義パラメータの1つの対応関係を1つのレコードと称する。リストは、複数のレコードを含み得る。要素名は、ソースファイルに記述されたシンボル(あるいはオブジェクト)の名称である。すなわち、要素は、シンボル(あるいはオブジェクト)を示す。使用フラグは、当該要素名に対応するシンボルに対してdeprecated属性に応じた非推奨警告がコンパイル時に発生したか否かを示すフラグである。使用フラグ“FALSE”は、当該シンボルに対して非推奨警告の出力の指示が発生しなかったことを示す。使用フラグ“TRUE”は、当該シンボルに対して非推奨警告の出力の指示が発生したことを示す。ユーザ定義パラメータは、シンボルに対して付与されたdeprecated属性が、ユーザ定義のものか、または、属性追加部161により追加されたものかの識別結果を示すパラメータである。ユーザ定義パラメータ“X”は、ユーザ定義のものではないこと(すなわち、属性追加部161により追加されたものであること)を示す。ユーザ定義パラメータ“Y”は、ユーザ定義のものであること(すなわち、属性追加部161により追加されたものでないこと)を示す。
最適化部171は、中間コード記憶部120に記憶された中間コードを用いて、中間コード単位(すなわち、コンパイル単位)の最適化処理を行う。例えば、最適化部171の最適化処理により、プログラムの実行の所要時間の短縮やメモリ使用量の低減などが図られる。
出力生成部172は、最適化部171による最適化結果に基づいて、オブジェクトファイルを生成し、オブジェクトファイル記憶部130に格納する。このとき、出力生成部172は、警告出力部162により提供されたリストを、オブジェクトファイルに追加する。例えば、ソースファイル111に対するコンパイルを行う場合、出力生成部172は、ソースファイル111に対応するオブジェクトファイル131を、オブジェクトファイル記憶部130に格納する。オブジェクトファイル131は、ソースファイル111に関して、deprecated属性に応じた各シンボルの非推奨警告の有無が記録されたリストL10を含む。また、ソースファイル112に対するコンパイルを行う場合、出力生成部172は、ソースファイル111に対応するオブジェクトファイル132を、オブジェクトファイル記憶部130に格納する。オブジェクトファイル132は、ソースファイル112に関して、deprecated属性に応じた各シンボルの非推奨警告の有無が記録されたリストL20を含む。
LTO処理部181は、リンカの機能を提供する。具体的には、LTO処理部181は、オブジェクトファイル記憶部130に記憶された複数のオブジェクトファイルに対するリンク処理を実行する。LTO処理部181は、リンク処理においてLTOを実行する。LTO処理部181は、リンク処理を実行することで実行ファイルを生成する。LTO処理部181は、生成された実行ファイルを実行ファイル記憶部140に格納する。
リスト結合部182は、LTO処理部181によるLTO実行の際に、リンク対象の各オブジェクトファイルに含まれるリストを取得する。リスト結合部182は、取得された複数のリストを結合(マージ)し、マージ後のリストを作成する。例えば、LTO処理部181によりオブジェクトファイル131,132のリンク処理が行われる場合、リスト結合部182は、オブジェクトファイル131に含まれるリストL10、および、オブジェクトファイル132に含まれるリストL20を取得する。そして、リスト結合部182は、リストL10,L20をマージし、マージ後のリストを作成する。
結果出力部183は、リスト結合部182により作成されたリスト(結合後のリスト)を参照して、オブジェクトファイル131,132にわたって未使用であるシンボル(未使用シンボル)を特定する。結果出力部183は、未使用シンボルの情報を出力する。例えば、結果出力部183は、ソースファイル111,112に、未使用シンボルが存在することを示す警告メッセージを、ディスプレイ11により表示させる。
ここで、ソースファイル記憶部110、中間コード記憶部120、オブジェクトファイル記憶部130および実行ファイル記憶部140は、RAM102またはHDD103に確保された所定の記憶領域を用いて実現される。
また、字句解析部151、構文解析部152、意味解析部153、属性追加部161、警告出力部162、最適化部171、出力生成部172、LTO処理部181、リスト結合部182および結果出力部183の機能は、プロセッサ101により実現される。例えば、プロセッサ101は、RAM102に記憶された所定のプログラムを実行することで、字句解析部151、構文解析部152、意味解析部153、属性追加部161、警告出力部162、最適化部171、出力生成部172、LTO処理部181、リスト結合部182および結果出力部183の機能を発揮する。これらの機能は、コンパイラと呼ばれるソフトウェアの機能として実装される。ただし、字句解析部151、構文解析部152、意味解析部153、属性追加部161、警告出力部162、最適化部171および出力生成部172の機能をコンパイラに実装し、LTO処理部181、リスト結合部182および結果出力部183の機能をリンカに実装する、というように、別個のソフトウェアとして各機能を実装することもできる。
図10は、ソースファイルの例(その1)を示す図である。ソースファイル111のファイル名は、“sample.cpp”である。ソースファイル111では、“int global_y;”に対して“[[deprecated]]”が付されている(ソースファイル111の3行目)。これは、“global_y;”の使用が非推奨である旨の警告メッセージを通知するために、ユーザによって追加されたdeprecated属性である。
図11は、ソースファイルの例(その2)を示す図である。ソースファイル112のファイル名は、“main.cpp”である。ソースファイル112では、ソースファイル111と同様に、“int global_y;”に対して“[[deprecated]]”が付されている(ソースファイル112の4行目)。これは、“global_y;”の使用が非推奨である旨の警告メッセージを通知するために、ユーザによって追加されたdeprecated属性である。
図10,図11で例示したように、ソースファイル111,112には、deprecated属性による本来の警告メッセージを通知するために、ユーザによってdeprecated属性が予め付与されることがある。したがって、コンパイラ装置100は、このような本来通知すべき警告メッセージに絞って、ユーザに提示する機能も提供する。
図12は、構文木の例(その1)を示す図である。図12では、ソースファイル111に対応する構文木51,52,53,54,55,56,57を例示している。
構文木51は、ソースファイル111の2行目のコードに相当する。構文木52は、ソースファイル111の3行目のコードに相当する。構文木53は、ソースファイル111の5行目〜8行目のコードに相当する。構文木54は、ソースファイル111の9行目のコードに相当する。構文木55は、ソースファイル111の11行目〜13行目のコードに相当する。構文木56は、ソースファイル111の15行目〜16行目のコードに相当する。構文木57は、ソースファイル111の18行目〜20行目のコードに相当する。
構文木は、ソースファイル111に記述された字句をノードとし、字句間の連結関係をエッジとした木構造をもつ情報である。例えば、ソースファイル111の2行目では、“int”という整数型を表す文字列に、“global_x”の文字列が続く。このため、構文木51では、型(Type)として“int”をもつノードと、変数(Variable)として“global_x”をもつノードとをエッジにより繋ぐ。
このように、構文木のノードは、型(Type)や変数(Variable)といった属性をもつ。クラスキー(Class key)を用いて、クラスの型が定義される場合、Typeのノードには、Class keyのノード(“struct”、“class”または“union”といった値をもつ)が接続される。ノードの属性は、型や変数以外にも次のものが例示される。
第1には、“static”や“const”などの修飾子(Qualifier)である。第2には、関数名などに相当するルーチン(Routine)である。第3には、deprecated属性などに相当する属性(attribute)である。
第4には、数式(expression)、繰り返し(iteration)、呼び出し(call)、および、リターン(return)などに相当するステートメント(Statement)である。
例えば、ステートメントとして、“expression”をもつノードには、演算子(Operator)の属性をもつノード(例えば、演算子“=”が設定される)が連結される。そして、演算子のノードに対して、当該演算子で結ばれる変数(例えば、変数“x”および変数“global_y”)が連結される。
また、例えば、ステートメントとして“call”をもつノードには、呼び出す関数名などのノードが連結される。更に、ステートメントとして“return”をもつノードには、呼び出し元の関数に対する戻り値(返り値)が設定されたノードが連結される。
図13は、構文木の例(その2)を示す図である。図13では、ソースファイル112に対応する構文木61,62,63,64を例示している。
構文木61は、ソースファイル112の2行目〜8行目のコードに相当する。構文木62は、ソースファイル112の10行目〜13行目のコードに相当する。構文木63は、ソースファイル112の14行目のコードに相当する。構文木64は、ソースファイル112の16行目〜20行目のコードに相当する。
構文木61,62,63,64も、ソースファイル112に記述された字句をノードとし、字句間の連結関係をエッジとした木構造をもつ。
図14は、deprecated属性の追加例を示す図である。deprecated属性は、C++の規約に従って付与されなければ、コンパイラによって適切に処理されない。すなわち、deprecated属性は、どこにでも付与できるわけではなく、言語規格で付与できる場所が定められている。特に、クラスの静的メンバ変数にdeprecated属性を付与する際に注意を要する。サンプルコード111pは、ソースファイル111の一部のコードにdeprecated属性を追加したものである。ここで、「クラス」という場合、構造体を含むものとする。
サンプルコード111pの6行目の“[[deprecated]] int x;”の記述は許容される。一方、サンプルコード111pの7行目の“[[deprecated]] static int y;”の記述は、許容されない。ここで、サンプルコード111pの7行目の「未定義な動作」(undefined behavior)とは、ISO/IEC 13382:2014では定められておらず、使用するコンパイラによって振る舞いが変わる処理のことである。実質クラスの静的メンバ変数の宣言にdeprecated属性を付与する場合、C++の規約では、静的変数の実体に付与することが求められる。したがって、サンプルコード111pの9行目の“[[deprecated]] int X::y;”の記述が適正となる。
このような理由から、属性追加部161は、意味解析部153によるソースコードの意味解析処理の結果を基に、deprecated属性をC++の規約で定められた適切な箇所に付与する。
なお、前述の“int x”(サンプルコード111pの6行目)のようなローカル変数は、既存の警告機能でも検出可能である。コンパイラ装置100では、複数のファイル間で使用されていない機能を検出するために、ファイルを跨いだ参照や呼び出しが生じ得る以下の内容をdeprecated属性の主な付与対象(ターゲット)とする。
第1のターゲットは、グローバル変数である。第2のターゲットは、関数である。第3のターゲットは、クラス(構造体を含む)である。第4のターゲットは、クラスのメンバ変数である。第5のターゲットは、クラスの静的メンバ変数である(ただし、前述のように静的メンバ変数の実体)。第6のターゲットは、クラスのメンバ関数である。第7のターゲットは、列挙型である。第8のターゲットは、共用体である。
このため、属性追加部161は、deprecated属性を付与する際に、付与対象が適切であるかを確認する。
図15は、LTOを用いる場合のコマンド例を示す図である。ユーザは、コマンド“g++−6.1.0 sample.cpp 0fast flto c o sample.o”を、コンパイラ装置100に入力することで、コンパイラ装置100によるソースファイル111のコンパイルを指示する。このとき、ユーザは、オプション“flto”を指定することで、後段のLTO処理を意識したオブジェクトファイルの生成を、コンパイラ装置100に指示できる。コンパイラ装置100は、当該コマンドの入力に応じて、ソースファイル111をコンパイルし、オブジェクトファイル131を生成する。前述のように、オブジェクトファイル131は、LTO処理に用いられる中間表現の情報を含む。また、オブジェクトファイル131は、リストL10を含む。
同様に、ユーザは、コマンド“g++−6.1.0 main.cpp 0fast flto c o main.o”を、コンパイラ装置100に入力することで、コンパイラ装置100によるソースファイル112のコンパイルを指示する。コンパイラ装置100は、当該コマンドの入力に応じて、ソースファイル112をコンパイルし、オブジェクトファイル132を生成する。前述のように、オブジェクトファイル132は、LTO処理に用いられる中間表現の情報を含む。また、オブジェクトファイル132は、リストL20を含む。
次に、コンパイラ装置100により実行される処理手順を説明する。
図16は、第2の実施の形態のコンパイル例を示すフローチャートである。以下、図16に示す処理をステップ番号に沿って説明する。
(S11)字句解析部151は、ソースファイル111に対するコンパイルコマンドを受け付ける。コンパイルコマンドは、例えば、図15の1行目で示されるコマンドである。コンパイル対象がソースファイル112の場合は、例えば図15の2行目で示されるコマンドが用いられる。
(S12)字句解析部151は、ソースファイル111に対する字句解析を行う。また、構文解析部152は、字句解析部151による字句解析の結果に基づいて、ソースファイル111の構文解析を行い、構文木51,52,53,54,55,56,57の情報を生成し、RAM102の所定の記憶領域に格納する。更に、意味解析部153は、RAM102に記憶された構文木51,52,53,54,55,56,57の情報に基づいて、意味解析を行い、解析結果を属性追加部161に通知する。
(S13)属性追加部161は、意味解析部153による意味解析の結果に基づいて、構文木51,52,53,54,55,56,57それぞれに含まれる所定のシンボルにdeprecated属性を追加する。処理の詳細は後述される。
(S14)警告出力部162は、deprecated属性に応じた非推奨機能に対する警告出力を行う。処理の詳細は後述される。
(S15)意味解析部153は、意味解析の結果に基づいて、ソースファイル111に対応する中間コードを生成し、中間コード記憶部120に格納する。最適化部171は、中間コード記憶部120に記憶された中間コードを用いて所定の最適化処理を実行する。出力生成部172は、最適化部171による最適化結果を用いて、ソースファイル111に対応するオブジェクトファイル131を生成し、オブジェクトファイル記憶部130に格納する。このとき、出力生成部172は、警告出力部162により作成されたリストL10を取得し、オブジェクトファイル131に追加する。
このようにして、コンパイラ装置100は、ソースファイル111をコンパイルし、オブジェクトファイル131を作成する。コンパイラ装置100は、ソースファイル112についても同様にして、オブジェクトファイル132を作成する。
図17は、第2の実施の形態の属性追加例を示すフローチャートである。以下、図17に示す処理をステップ番号に沿って説明する。以下に示す手順は、図16のステップS13に相当する。
(S21)属性追加部161は、RAM102に記憶された構文木51,52,53,54,55,56,57のうち、未処理の構文木(ステップS22以降の処理を行っていない構文木)があるか否かを判定する。未処理の構文木がある場合、属性追加部161は、未処理の構文木を1つ選択して、ステップS22に処理を進める。未処理の構文木がない場合、属性追加部161は、処理を終了する。
(S22)属性追加部161は、該当の構文木がグローバル変数の宣言であるか否かを判定する。グローバル変数の宣言である場合、属性追加部161は、ステップS27に処理を進める。グローバル変数の宣言でない場合、属性追加部161は、ステップS23に処理を進める。例えば、属性追加部161は、該当の構文木が、プログラム中の、構造体や関数などに相当するブロックに属さない箇所で宣言された変数である場合に、当該構文木をグローバル変数の宣言であると判定する。該当の構文木が、プログラム中の、構造体や関数などに相当するブロックに属さない箇所で宣言された変数でない場合、属性追加部161は、当該構文木をグローバル変数の宣言でないと判定する。
(S23)属性追加部161は、該当の構文木が列挙型の定義であるか否かを判定する。列挙型の定義である場合、属性追加部161は、ステップS27に処理を進める。列挙型の定義でない場合、属性追加部161は、ステップS24に処理を進める。例えば、属性追加部161は、該当の構文木が、Type“enum”による定義の場合、該当の構文木は列挙型の定義であると判定する。該当の構文木が、Type“enum”による定義でない場合、属性追加部161は、該当の構文木は列挙型の定義ではないと判定する。
(S24)属性追加部161は、該当の構文木が共用体の定義であるか否かを判定する。共用体の定義である場合、属性追加部161は、ステップS27に処理を進める。共用体の定義でない場合、属性追加部161は、ステップS25に処理を進める。例えば、属性追加部161は、該当の構文木がClass key“union”のノードをもつ場合、該当の構文木は共用体の定義であると判定する。該当の構文木が、Class key“union”のノードをもたない場合、属性追加部161は、該当の構文木は共用体の定義ではないと判定する。
(S25)属性追加部161は、該当の構文木が関数の定義であるか否かを判定する。関数の定義である場合、属性追加部161は、ステップS27に処理を進める。関数の定義でない場合、属性追加部161は、ステップS26に処理を進める。例えば、属性追加部161は、該当の構文木がRoutineのノードをルートとする場合、該当の構文木は関数の定義であると判定する。該当の構文木が、Routineのノードをルートとしない場合、該当の構文木は関数の定義でないと判定する。ただし、属性追加部161は、Routineのノードがmain関数を表す場合、例外的にdeprecated属性の付与対象外とするため、ステップS21に処理を進める。
(S26)属性追加部161は、該当の構文木がクラスの定義であるか否かを判定する。クラスの定義である場合、属性追加部161は、ステップS27に処理を進める。クラスの定義でない場合、属性追加部161は、ステップS21に処理を進める。例えば、属性追加部161は、該当の構文木がClass key“struct”またはClass key“class”のノードをもつ場合、該当の構文木はクラスの定義であると判定する。該当の構文木がClass key“struct”またはClass key“class”のノードをもたない場合、属性追加部161は、該当の構文木はクラスの定義ではないと判定する。
(S27)属性追加部161は、該当の構文木のオブジェクトをリストL10に記録する。属性追加部161は、該当のオブジェクトがクラスならば静的メンバ変数以外のメンバ変数と、各メンバ関数もリストL10に記録する。なお、あるソースファイルのコンパイル時に最初にステップS27を実行する直前に、属性追加部161は、該当のソースファイルに対するリスト(当初は何も記録されていない空のリスト)を作成し、RAM102の所定の記憶領域に格納する。
(S28)属性追加部161は、ユーザ定義の[[deprecated]]属性(deprecated属性)が該当の構文木に付与されているか否かを判定する。ユーザ定義のdeprecated属性が該当の構文木に付与されている場合、属性追加部161は、ステップS29に処理を進める。ユーザ定義のdeprecated属性が該当の構文木に付与されていない場合、属性追加部161は、ステップS30に処理を進める。
(S29)属性追加部161は、リストL10における同オブジェクトのパラメータ(具体的には、ユーザ定義パラメータ)に“Y”を記録する。そして、属性追加部161は、ステップS21に処理を進める。
(S30)属性追加部161は、リストL10における同オブジェクトのパラメータ(具体的には、ユーザ定義パラメータ)に“X”を記録する。
(S31)属性追加部161は、該当の構文木にdeprecated属性を追加する。具体的には、属性追加部161は、ステップS27において、リストL10に記録された構文木のオブジェクトのノードに対して、attributeのノードを連結し、当該attributeのノードに、“[[deprecated]]”を設定する。なお、該当のオブジェクトがクラスの場合には、属性追加部161は、静的メンバ変数以外のメンバ変数と、各メンバ関数に対しても、同様にして、deprecated属性を追加する。そして、属性追加部161は、ステップS21に処理を進める。
なお、上記の説明では、ソースファイル111のコンパイル時における属性追加の手順を説明したが、属性追加部161は、ソースファイル112に対しても同様にして属性追加を行う。
また、ステップS22の変数の確認において、属性追加部161は、構文木がクラスの静的メンバ変数の実体の定義であるか否かの確認を含めることができる。例えば、構文木54のように、スコープ解決演算子“::”を用いたクラス“X”の静的メンバ変数“X::y”の実体の定義の場合、属性追加部161は、ステップS27に処理を進める。そして、属性追加部161は、当該オブジェクトの要素名およびユーザ定義パラメータのリストL10への登録やdeprecated属性の追加を行う。
図18は、リストの例(その1)を示す図である。リストL11は、ソースファイル111(ファイル名“sample.cpp”)のコンパイルの過程(図17の手順の直後の段階)で、属性追加部161により作成されたリストの例である。リストL11は、リストL10に至る前段階の状態を表している。リストL11は、要素名、使用フラグおよびユーザ定義パラメータの項目を含む。
例えば、リストL11は、要素名が“int global_x”、使用フラグが設定なし(図中、ハイフン記号“−”により設定なしを表している)、ユーザ定義パラメータが“X”というレコードを含む。これは、“int global_x”というプログラム要素がソースファイル111に存在し、非推奨警告の有無を未判定であること、“int global_x”に対しユーザ定義のdeprecate属性がないことを示す。この場合、“int global_x”に対して、属性追加部161により、deprecated属性が追加されたことになる。
また、リストL11は、要素名が“int global_y”、使用フラグが設定なし、ユーザ定義パラメータが“Y”というレコードを含む。これは、“int global_y”というプログラム要素がソースファイル111に存在し、非推奨警告の有無が未判定であること、“int global_y”に対しユーザ定義のdeprecated属性があることを示す。
リストL11には、ソースファイル111に含まれる他のプログラム要素(ただし、deprecated属性の付与対象の要素)に対しても、同様に、要素名と、使用フラグと、ユーザ定義パラメータとの対応関係が登録される。ただし、図17の手順が完了した段階では、使用フラグは設定なしである。
図19は、リストの例(その2)を示す図である。リストL21は、ソースファイル112(ファイル名“main.cpp”)のコンパイルの過程(図17の手順の直後の段階)で、属性追加部161により作成されたリストの例である。リストL21は、リストL20に至る前段階の状態を表している。リストL21は、要素名、使用フラグおよびユーザ定義パラメータの項目を含む。
リストL21には、ソースファイル112に含まれるプログラム要素(ただし、deprecated属性の付与対象の要素)に対して、リストL11と同様に、要素名と、使用フラグと、ユーザ定義パラメータとの対応関係が登録される。ただし、図17の手順が完了した段階では、使用フラグは設定なしである。
図20は、構文木(deprecated追加後)の例(その1)を示す図である。構文木51a,52a,53a,54a,55a,56a,57aは、構文木51,52,53,54,55,56,57に対してdeprecated属性を追加した状態を示す。特に、構文木53aでは、構造体“X”に対して“[[deprecated]]”が追加され、更に、構造体“X”の静的メンバ変数以外のメンバ変数“x”に対しても“[[deprecated]]”が追加されている。一方、構文木53aでは、構造体“X”の静的メンバ変数“y”には、“[[deprecated]]”が追加されていない。その代わり、構文木54aの静的メンバ変数“y”の実体の定義に対して、“[[deprecated]]”が追加されている。
図21は、構文木(deprecated追加後)の例(その2)を示す図である。構文木61a,62a,63aは、構文木61,62,63に対してdeprecated属性を追加した状態を示す。なお、構文木64は、main関数を表す構文木であるため、前述のようにdeprecated属性が追加されない。
図22は、第2の実施の形態の非推奨機能に対する警告出力例を示すフローチャートである。以下、図22に示す処理をステップ番号に沿って説明する。
(S41)警告出力部162は、今回のコンパイル対象であるソースファイル111に対して作成されたリストL11を、RAM102の所定の記憶領域から取得する。
(S42)警告出力部162は、リストL11に未処理の要素(ステップS43以降の処理を行っていない要素)があるか否かを判定する。未処理の要素がある場合、警告出力部162は、ステップS43に処理を進める。未処理の要素がない場合、警告出力部162は、処理を終了する。
(S43)警告出力部162は、[[deprecated]]属性(deprecated属性)の機能による非推奨警告の応答があるかを確認する。例えば、警告出力部162は、意味解析部153によるdeprecated属性付与後の各構文木の意味解析の結果として、deprecated属性の機能による非推奨警告が該当の要素に対して発生しているかを確認する。
(S44)警告出力部162は、ステップS43の確認により、該当の要素に対して、非推奨警告があるか否かを判定する。該当の要素に対して非推奨警告がある場合、警告出力部162は、ステップS45に処理を進める。該当の要素に対して非推奨警告がない場合、警告出力部162は、ステップS49に処理を進める。
(S45)警告出力部162は、該当の要素を使用されている機能であると決定する。
(S46)警告出力部162は、リストL11を参照して、該当の要素に対するユーザ定義パラメータが“Y”であるか否かを判定する。該当の要素に対するユーザ定義パラメータが“Y”である場合、警告出力部162は、ステップS47に処理を進める。該当の要素に対するユーザ定義パラメータが“Y”でない場合(すなわち、“X”である場合)、警告出力部162は、ステップS48に処理を進める。
(S47)警告出力部162は、該当の要素が非推奨機能である旨の警告を、ディスプレイ11に表示させる。
(S48)警告出力部162は、リストL11において、該当の要素の使用フラグを“TRUE”に設定する。そして、警告出力部162は、ステップS42に処理を進める。
(S49)警告出力部162は、該当の要素を使用されていない機能であると決定する。
(S50)警告出力部162は、リストL11において、該当の要素の使用フラグを“FALSE”に設定する。そして、警告出力部162は、ステップS42に処理を進める。
ここで、ステップS45,S49の決定を行える理由は次の通りである。本来、deprecated属性による非推奨である旨の警告機能は、該当のオブジェクト(要素)が“使用された場合”にコンパイラが警告をだす機能である。本機能を一考すると、deprecated属性が付与されたオブジェクトのうち、コンパイラによって「非推奨である旨の警告がでないものは使用されていない」と考えることができる。したがって、deprecated属性が付与された要素についてコンパイラによる非推奨警告が発生していれば、当該要素は使用されている機能であると考えられる。一方、deprecated属性が付与された要素についてコンパイラによる非推奨警告が発生していなければ、当該要素は使用されていない機能であると考えられる。
そして、ステップS43〜S50の手順で示されるように、コンパイラ装置100は、deprecated属性に対する警告の出力処理に併せて、deprecated属性に対する警告の有無により未使用シンボルを決定する。すなわち、コンパイラ装置100は、コンパイル時のdeprecated属性に対する警告の出力処理の手順の中で、未使用シンボルを決定する。より具体的には、警告出力部162は、deprecated属性に対する警告があれば、deprecated属性が付与された該当のシンボルを使用されていると決定する。また、警告出力部162は、deprecated属性に対する警告がなければ、deprecated属性が付与された該当のシンボルを未使用であると決定する。
このため、未使用シンボルを決定するためのルーチンを、コンパイルと別個に行わずに済む。具体的には、コンパイルとは別個に、各シンボルが使用されているか否かのチェック処理を行わなくてよくなる。これにより、コンパイル装置100は、未使用シンボルの抽出を効率的に行える。また、未使用シンボルを抽出するためのルーチンを別個に行うよりも、未使用シンボルの抽出を高速化できる。
また、コンパイラ装置100は、ステップS46の判定により、ユーザにより予めdeprecated属性が付与されていた要素(シンボル)に絞って、非推奨警告をディスプレイ11による表示対象とすることができる。すなわち、コンパイラ装置100は、属性追加部161によりdeprecated属性が追加された要素(シンボル)に対する非推奨警告のディスプレイ11による表示を制限する。これにより、ユーザにより非推奨警告の表示が意図されている要素に絞って非推奨警告を表示させることができる。
図23は、使用フラグ設定後のリストの例を示す図である。図23(A)は、リストL10の内容を示す。リストL10は、リストL11に対して、使用フラグが設定された後の状態である。図23(B)は、リストL20の内容を示す。リストL20は、リストL21に対して、使用フラグが設定された後の状態である。
リストL10の例でいえば、ソースファイル111における“int global_x”、“struct X”、“int X::x”(構造体“X”のメンバ変数“x”)、“static int X::y”、“void func01()”および“void func03()”の各要素に対応する使用フラグは、“FALSE”である。これは、ソースファイル111において、“int global_x”、“struct X”、“int X::x”(構造体“X”のメンバ変数“x”)、“static int X::y”、“void func01()”および“void func03()”の各要素は使用されていないことを示す。
一方、リストL10では、ソースファイル111における“int global_y”および“void func02()”の各要素に対応する使用フラグは、“TRUE”である。これは、ソースファイル111において、“int global_y”および“void func02()”の各要素は使用されていることを示す。
同様に、リストL20の例でいえば、ソースファイル112における“int global_y”、“void func01(void)”、“void func02(void)”、“struct X”、“int X::x”および“static int X::y”の各要素に対応する使用フラグは、“FALSE”である。これは、ソースファイル112において、“int global_y”、“void func01(void)”、“void func02(void)”、“struct X”、“int X::x”および“static int X::y”の各要素は使用されていないことを示す。
一方、リストL20では、ソースファイル112における“int global_x”および“void func03(void)”の各要素に対応する使用フラグは、“TRUE”である。これは、ソースファイル112において、“int global_x”および“void func03(void)”の各要素は使用されていることを示す。
リストL10は、オブジェクトファイル131に追加される。また、リストL20は、オブジェクトファイル132に追加される。そして、オブジェクトファイル131,132は、オブジェクトファイル記憶部130に格納される。
次に、以上のようにして生成されたオブジェクトファイル131,132に基づく実行ファイルの生成処理の手順を説明する。コンパイラ装置100は、オブジェクトファイル131,132を結合する(リンク処理する)ことで、実行ファイルを生成する。
図24は、第2の実施の形態のリンク処理例を示すフローチャートである。以下、図24に示す処理をステップ番号に沿って説明する。
(S61)LTO処理部181は、実行ファイルの生成指示コマンドを受け付ける。実行ファイルの生成指示コマンドは、例えば、図15の3行目で示されるコマンドである。例えば、当該コマンドでは、リンク対象として、オブジェクトファイル記憶部130に記憶されたオブジェクトファイル131,132が指定される。
(S62)LTO処理部181は、オブジェクトファイル131,132に基づいてリンク時最適化(LTO)処理を実行する。このとき、LTO処理部181は、リンク対象のオブジェクトファイル131からリストL10を抽出し、リスト結合部182に提供する。また、LTO処理部181は、リンク対象のオブジェクトファイル132からリストL20を抽出し、リスト結合部182に提供する。
(S63)リスト結合部182は、LTO処理部181から取得したリストL10,L20に基づいて、未使用機能に対する警告出力の処理を実行する。当該処理の詳細は後述される。
(S64)LTO処理部181は、オブジェクトファイル131,132に基づいて実行ファイルを生成し、生成された実行ファイルを出力する。具体的には、LTO処理部181は、生成された実行ファイルを、実行ファイル記憶部140に格納する。
図25は、第2の実施の形態の未使用機能に対する警告出力例を示すフローチャートである。以下、図25に示す処理をステップ番号に沿って説明する。以下に示す手順は、図24のステップS63に相当する。
(S71)リスト結合部182は、LTO処理部181によるLTO処理の際にオブジェクトファイル131,132から抽出されたリストL10,L20を取得する。
(S72)リスト結合部182は、リストL10,L20をマージすることでマージ後のリストを作成する。具体的には、リスト結合部182は、リストL10,L20の少なくとも一方に含まれる要素名を、マージ後のリストの要素名の項目に登録する。また、リスト結合部182は、マージ後のリストに登録した要素名に対して、リストL10,L20それぞれの使用フラグを参照し、少なくとも一方の使用フラグが“TRUE”であれば、マージ後のリストの当該要素名に対する使用フラグを“TRUE”とする。両方の使用フラグが“FALSE”であれば、リスト結合部182は、マージ後のリストの当該要素名に対する使用フラグを“FALSE”とする。ユーザ定義パラメータについては、少なくとも何れか一方が“Y”であれば“Y”、両方が“X”であれば“X”とする。
ここで、リスト結合部182は、リストL10,L20において実質的に同じ要素名があれば、当該要素名がリストL10,L20の両方に存在すると判断する。例えば、リストL10における“void func01()”と、リストL20における“void func01(void)”とは、実質的に同じである。したがって、リスト結合部182は、当該要素について、リストL10,L20のうちの一方に登録された要素名(例えば、“void func01(void)”)を採用し、マージ後のリストに追加する。リスト結合部182は、作成したリストをRAM102の所定の記憶領域に格納する。
(S73)結果出力部183は、マージ後のリストに未処理の要素があるか否かを判定する。マージ後のリストに未処理の要素(ステップS74以降の処理を行っていない要素)がある場合、結果出力部183は、ステップS74に処理を進める。マージ後のリストに未処理の要素がない場合、結果出力部183は、処理を終了する。
(S74)結果出力部183は、マージ後のリストの要素を1つ選択する。ここで選択対象となる要素は、未だ選択されていない要素である。
(S75)結果出力部183は、マージ後のリストを参照して、該当の要素に対応する使用フラグが“FALSE”であるか否かを判定する。“FALSE”である場合、結果出力部183は、ステップS76に処理を進める。“FALSE”でない場合(すなわち、“TRUE”である場合)、結果出力部183は、ステップS73に処理を進める。
(S76)結果出力部183は、該当の要素について、使用されていない機能である旨の警告をディスプレイ11に表示させる。そして、結果出力部183は、ステップS73に処理を進める。
図26は、マージ後のリストの例を示す図である。リストL30は、リストL10,L20をマージした結果である。例えば、リストL30には各要素について次のように使用フラグが決定される。
要素名“int global_x”について、リストL10の使用フラグは“FALSE”であり、リストL20の使用フラグは“TRUE”である。したがって、リストL30の要素名“int global_x”の使用フラグは“TRUE”である。
要素名“int global_y”について、リストL10の使用フラグは“TRUE”であり、リストL20の使用フラグは“FALSE”である。したがって、リストL30の要素名“int global_y”の使用フラグは“TRUE”である。
要素名“struct X”について、リストL10の使用フラグは“FALSE”であり、リストL20の使用フラグは“FALSE”である。したがって、リストL30の要素名“struct X”の使用フラグは“FALSE”である。
要素名“int X::x”について、リストL10の使用フラグは“FALSE”であり、リストL20の使用フラグは“FALSE”である。したがって、リストL30の要素名“int X::x”の使用フラグは“FALSE”である。
要素名“static int X::y”について、リストL10の使用フラグは“FALSE”であり、リストL20の使用フラグは“FALSE”である。したがって、リストL30の要素名“static int X::y”の使用フラグは“FALSE”である。
要素名“void func01(void)”について、リストL10の使用フラグは“FALSE”であり、リストL20の使用フラグは“FALSE”である。したがって、リストL30の要素名“void func01(void)”の使用フラグは“FALSE”である。
要素名“void func02(void)”について、リストL10の使用フラグは“TRUE”であり、リストL20の使用フラグは“FALSE”である。したがって、リストL30の要素名“void func02(void)”の使用フラグは“TRUE”である。
要素名“void func03(void)”について、リストL10の使用フラグは“FALSE”であり、リストL20の使用フラグは“TRUE”である。したがって、リストL30の要素名“void func03(void)”の使用フラグは“TRUE”である。
結果出力部183は、リストL30に基づいて、ソースファイル111,112における“struct X”、“int X::x”、“static int X::y”および“void func01(void)”に相当するコードが未使用である旨の警告を、ディスプレイ11に表示させる。
図27は、未使用を示す警告の表示例を示す図である。メッセージ群11bは、該当の要素が未使用であることを示す警告メッセージの表示例である。例えば、結果出力部183は、リストL30における該当の要素名からソースファイル111,112における記述箇所を特定する。そして、結果出力部183は、ソースファイル111,112それぞれのファイル名と、当該記述箇所を示す情報(例えば、行番号や行先頭からの位置を表す番号など)とをディスプレイ11に表示させてもよい。
このように、コンパイラ装置100は、deprecated属性による非推奨警告の出力機能を活用して、ソースコード中の未使用の要素の抽出を行う。これにより、ソースコード中の未使用の要素の抽出機能をコンパイラに対して容易に実装可能になる。すなわち、コード中の未使用の要素の抽出機能をコンパイラの一部の機能として、または、コンパイラの追加機能として容易に実現可能となる。
更に、コンパイラ装置100は、deprecated属性に対する警告の出力処理に併せて、deprecated属性に対する警告の有無により未使用シンボルを決定する。このため、未使用シンボルを決定するためのルーチンを、コンパイルと別個に行わずに済む。具体的には、コンパイルとは別個に、各シンボルが使用されているか否かのチェック処理を行わなくてよくなる。これにより、コンパイル装置100は、未使用シンボルの抽出を効率的に行える。また、未使用シンボルを抽出するためのルーチンを別個に行うよりも、未使用シンボルの抽出を高速化できる。
また、コンパイラ装置100は、ソースファイル111,112における未使用の要素をユーザに提示することで、ユーザによるソースコードの見直し箇所の特定を支援することができる。また、コンパイラ装置100は、リストL30を用いて、コンパイルの効率化を図ることもできる。具体的には次の通りである。
図28は、コンパイラ装置の他の機能例を示す図である。例えば、コンパイラ装置100は、図9で例示した機能に加えて、リスト記憶部190およびコンパイル制御部191を更に有してもよい。リスト記憶部190は、RAM102やHDD103の所定の記憶領域を用いて実現される。コンパイル制御部191は、プロセッサ101がRAM102に記憶されたプログラムを実行することで実現される。
リスト記憶部190は、リスト結合部182により生成されたリストL30を、ソースファイル111,112のファイル名に対応付けて記憶する。
コンパイル制御部191は、リスト記憶部190に記憶された情報に基づいて、ソースファイルにおけるコンパイル対象箇所を絞り込む。具体的には、コンパイル制御部191は、コンパイルの対象となるソースファイルに対して作成済のリストを、リスト記憶部190から検索し、当該リストにおいて使用フラグが“FALSE”である要素を、コンパイルの対象外に設定する。例えば、コンパイル制御部191は、コンパイラに対して該当の要素をコンパイルの対象外とすることを指示する所定のメタデータを、対象のソースファイルに追加してもよい。あるいは、コンパイル制御部191は、オリジナルのソースファイルからコンパイルの対象外とする要素を削除した新たなソースファイルを作成し、新たなソースファイルをコンパイルするようにコンパイラに指示してもよい。
次に、コンパイル制御部191の機能に基づくコンパイラ装置100の処理手順を説明する。
図29は、第2の実施の形態のコンパイル制御例を示すフローチャートである。以下、図29に示す処理をステップ番号に沿って説明する。
(S81)コンパイル制御部191は、コンパイルコマンドを受け付ける。コンパイルコマンドは、例えば、コンパイル対象のソースファイル111のファイル名を含む。
(S82)コンパイル制御部191は、指定されたソースファイルに対する作成済のリストが、リスト記憶部190にあるか否かを判定する。作成済のリストがある場合、コンパイル制御部191は、ステップS83に処理を進める。作成済のリストがない場合、コンパイル制御部191は、ステップS84に処理を進める。例えば、ソースファイル111に対する作成済のリストは、リストL30である。
(S83)コンパイル制御部191は、該当のリストで使用フラグが“FALSE”の要素をコンパイルの対象外に設定する。例えば、コンパイル制御部191は、ソースファイル111に含まれる要素のうち、リストL30において使用フラグが“FALSE”に設定されているものをコンパイルの対象外に設定する。前述のように、コンパイル制御部191は該当の要素をコンパイルの対象外とすることを指示する所定のメタデータを、ソースファイル111に追加してもよい。あるいは、コンパイル制御部191は、該当の要素を削除した新たなソースファイルを作成してもよい。後者の場合、コンパイル制御部191は、オリジナルのソースファイル111に代えて、当該新たなソースファイルによるコンパイルの開始をコンパイラ(例えば、そのうちの字句解析部151)に指示してもよい。
(S84)字句解析部151は、字句解析処理を開始する。以降、構文解析部152、意味解析部153、最適化部171および出力生成部172の一連の機能により、オブジェクトファイルが生成される(コンパイルが実行される)。なお、この場合、コンパイル制御部191は、属性追加部161によるdeprecated属性の追加処理を抑制してもよい。
このように、コンパイラ装置100は、作成済のリストL30に基づいてソースファイル111の中の使用されていない要素(シンボル)のコンパイルを省略することができる。コンパイラ装置100は、ソースファイル112についても同様に、リストL30に基づいて、ソースファイル112の中の使用されていない要素(シンボル)のコンパイルを省略することができる。
これにより、コンパイルの効率化を図れる。例えば、コンパイルに伴う処理を高速化し、コンパイルの所要時間を短縮することができる。
なお、第1の実施の形態の情報処理は、処理部1bにプログラムを実行させることで実現できる。また、第2の実施の形態の情報処理は、プロセッサ101にプログラムを実行させることで実現できる。プログラムは、コンピュータ読み取り可能な記録媒体13に記録できる。
例えば、プログラムを記録した記録媒体13を配布することで、プログラムを流通させることができる。また、プログラムを他のコンピュータに格納しておき、ネットワーク経由でプログラムを配布してもよい。コンピュータは、例えば、記録媒体13に記録されたプログラムまたは他のコンピュータから受信したプログラムを、RAM102やHDD103などの記憶装置に格納し(インストールし)、当該記憶装置からプログラムを読み込んで実行してもよい。