標準ドキュメント ジェネレータ バージョン 0.1

1 か月ほど前に、標準語の最初のプロトタイプをリリースしました。現在、ようやくバージョン 0.1 になりました。思ったよりも時間がかかりました。

一見しただけでは多くの機能が追加されることはありませんが、解析が大幅に改善されています。

foonathan/standardese は、Doxygen の代替となることを目的とした C++ 文書化ツールです。これは高度な開発段階であり、現在多くの機能をサポートしていません。しかし、すでに幅広い C++ のセットを解析し、Markdown で基本的な文書を生成することができます。

より良い解析

最初のプロトタイプを書いているときでさえ、すぐに libclang の限界にぶつかりました。

C++ コードの解析には優れていますが、必要なすべての情報を公開しているわけではありません。たとえば、コンストラクターが 07 かどうかなどです。 または 13 内の式 ですが、ドキュメントを書くときは、この情報が必要です。

そのため、コードを手動で解析して必要な情報をすべて取得する必要がありました。プロトタイプでは 23 を使用しました ただし、これには大きな制限があります。マクロとうまく混ざりません。

たとえば、次のような関数シグネチャがある場合:

void foo() FOONATHAN_NOEXCEPT;

トークン 31 を与えます 、展開先のトークンではありません。

そのため、いくつかの手動マクロ展開を実装しようとしましたが、複数のトークンに展開するより複雑なマクロではうまく機能しませんでした.できる マクロを使うのは良くない、気分が悪いと言うだけです。しかし、私には標準化における基本的な設計哲学があります。つまり、コードがコンパイルされたら、それを解析する必要があります。

したがって、別のソリューションが必要でした。トークン化に Boost.Wave を使用することにしました。libclang とは異なり、トークン化の前にソース コードを前処理します。すべてのマクロを登録し、ソース ファイルの適切なセクションを読み取るためのカーソル範囲を取得するだけで済みました。 .

マクロの登録は簡単です:48 を渡すと 、libclang は喜んですべての 54 を提供します s.これらはファイルの先頭にありますが、それは問題ではありません。すべての対応する定義は、ソース ファイルごとの前処理コンテキストで登録する必要があるだけで、全体で使用できます。

ソース エクステントを取得した 簡単ですが、完全ではありませんでした。libclang は関数 68 を提供します カーソルの範囲を返します。これは、いくつかの関数を使用してファイル内の実際のオフセットにマップできます。そのうちの 2 つは 70 です。 と 83 .それらは実質的に同じですが、マクロ展開を参照する場合、ファイルの場所は展開の場所であり、スペルの場所はマクロ定義の場所です.この場合、定義が必要なので、 を使用しました99 .

しかし、問題が発生したので、ソース コードを確認しました:

void clang_getSpellingLocation(CXSourceLocation location,
 CXFile *file,
 unsigned *line,
 unsigned *column,
 unsigned *offset) {
 ...
 
 const SourceManager &SM =
 *static_cast<const SourceManager*>(location.ptr_data[0]);
 // FIXME: This should call SourceManager::getSpellingLoc().
 SourceLocation SpellLoc = SM.getFileLoc(Loc);

 ....
}

しかし、それでもこの関数にはいくつかの問題があるようです。場合によっては、返されるソース範囲が短すぎて、重要な部分が切り取られます。たとえば:

using foo = unsigned int;

これで 103 になりました .これはいくつかの回避策につながります。

より肯定的な点として、属性のサポートも追加しました。実際には「サポート」ではなく、解析でスキップされるだけです。

私はするかもしれません エンティティの属性をどこかに保存しますが、それらのほとんどは重要ではないか、コメント属性によってサポートされます.しかし、それについての議論は受け付けています.

より堅牢な解析

初期のプロトタイプでは、パーサーが奇妙なことに遭遇した場合、アサーションは失敗し、すべてがクラッシュします。これはエラー回復の良い方法ではありません.

パーサーが奇妙なことに遭遇すると、例外がスローされます。この例外は最上位ループでキャッチされ、エラーがログに記録され、次のエンティティが解析されます。これは、すべての「悪い」エンティティが単純に無視されることを意味します。解析時ですが、それ以外はすべて解析されます。

たとえば、何らかの理由で解析コードが気に入らないクラスがある場合、そのクラス (およびすべてのメンバー) はスキップされ、その後も解析が続行されます。

ロギングは spdlog ライブラリで行われます。私はそれが本当に気に入っています。使いやすく、私のニーズに十分な機能をサポートし (主に公平なデバッグ レベル)、書式設定に fmt を使用します。これは 大きな プラス。

コンパイル構成

また、コンパイル オプションの構成のサポートも追加しました。これは、プロトタイプに欠けていた非常に基本的なことです。

インクルード ディレクトリとマクロ定義をコマンド ラインに直接渡すか、110 が含まれるディレクトリを渡すことができます。 ファイルが保存されます。

後者のアプローチの問題点の 1 つは次のとおりです。JSON ファイル内には、各 source のコンパイル コマンドがあります。 ファイルですが 121 ヘッダーのみが必要です 多くの場合、2 つの間に 1 対 1 のマッピングがないため、1 つのファイルにフラグを使用することはできません。

代わりに、すべて取る必要がありました すべてのフラグ 複数の「プロジェクト」からの翻訳単位がある場合、これは悪影響を与える可能性があります。

それを避けるために、CMake の特別なサポートも追加しました。136 を呼び出す場合 、関数 144 を取得します .この関数は、特定のターゲットのドキュメントを生成するカスタム ターゲットを作成します。コンパイル オプションを直接指定して、ヘッダー ファイルとインクルード ディレクトリの変数を共有することもできます。ただし、他のすべてのオプションは、外部構成ファイルを介して指定する必要があります。 .

詳細については、README を参照してください。

エンティティ フィルタリング

私が追加したより高度な機能の 1 つは、エンティティ フィルタリングです。ドキュメント生成からエンティティを非表示にします。

API ではより強力なフィルタリングが可能ですが、ツールには十分なオプションがあります。all をフィルタリングできます。 特定の名前または名前空間のみを持つエンティティ。また、プライベート エンティティを抽出するか (デフォルトで無効)、またはドキュメント コメントが必要か (デフォルトで有効) のフラグもあります。

しかし、このフィルタリングは非常にスマートです。次のコードを見てください:

namespace detail
{
 struct type {};
}

using type = detail::type;

名前空間 153 をフィルタリングする場合 、エイリアスの次の概要が表示されます:

using type = implementation-defined;

これはほとんどの場合に機能し、本当に 素晴らしい機能です。

162 を抽出しない場合 すべてを無視するだけではありません。 175 メンバー:185 をお持ちの場合 199 関数、それらはフィルター処理されません!これは、非仮想インターフェイス パターンをサポートします。

また、フィルタリングされたプライベート エンティティは概要から隠されていますが、ドキュメント コメントのないエンティティは引き続き含まれており、個別にドキュメント化されていません。

さらに何か?

このアップデートの変更リストは大規模ではありません 、では、なぜそんなに時間がかかったのですか?

答えは簡単です。目に見えない複数のリファクタリングやその他の内部変更を行いました。現在は全体の内部構造が異なり、他の機能をより簡単に処理できるようになります。

たとえば、エンティティのリンクの問題、つまりドキュメント内の他のエンティティを参照する問題に簡単に取り組むことができるようになりました。これは、次のバージョンの主な機能の 1 つになります。もう 1 つは、エンティティ合成です。つまり、ドキュメント コメントから C++ ソース コード エンティティを生成します。これは、変数テンプレートなど、libclang がサポートしていないものに特に役立ちます。その他の優れた機能。

そのため、標準語 0.2 が (できれば) それほど長くはかからないことを期待してください。それまでの間:標準語を見て、プロジェクトでテストしてください。また、それを共有して言葉を広めてください!