標準ドキュメント ジェネレータ バージョン 0.3:グループ、インライン ドキュメント、テンプレート モードなど

構文解析コードの 2 つのバグ修正リリースの後、最終的に標準語の機能をさらに実装するようになりました。内部コードの完全なリファクタリングにより、いくつかの高度な機能を実装することができました。標準語にはメンバー グループが付属し、インライン ドキュメントを表示する機能、テンプレート言語と、全体的なドキュメント生成を改善するだけの多くの小さなこと.

standardese は、C++ コード用に特別に設計されたドキュメント ジェネレーターです。C++ ドキュメントを記述するための多くのイディオムをサポートおよび検出します。Doxygen の代替となることを目指しています。

解析状況の更新

解析には libclang を使用していますが、多くの制限があるため、各エンティティのトークンに対して独自のパーサーを実行して必要な情報を取得する必要があります。

しかし、libclang のトークナイザーはトークンを前処理しないため、Boost.Wave を使用してトークンを前処理し、それらを解析しました。しかし、次の例のように、マクロによって生成されたソース エンティティがある場合、これは問題を引き起こします。 /P>

#define MAKE_STRUCT(name) \
struct name \
{ \
 int a; \
};

MAKE_STRUCT(foo)
MAKE_STRUCT(bar)

00 を解析する場合 または 13 、展開されたトークンの代わりに、マクロのトークンを取得します。C++ コードの記述方法に影響を与えたくないので、別のことをしなければなりませんでした。

0.2-2 パッチでは、前処理コードを変更して、Boost.Wave が 全体 を前処理するようにしました。 ファイルを作成し、それを libclang で解析します。そのため、前処理について心配する必要はありません。

ただし、Boost.Wave は遅い また、標準ライブラリ ヘッダーで使用される拡張機能の多くを処理できないため、多くの回避策を用意しました。

このバージョンでは、最終的に Boost.Wave を置き換え、今では前処理に clang を使用しています。

私は文字通り clang を使用して、23 でコードからバイナリを呼び出します 前処理出力を提供し、それを解析するためのフラグ。これが悪い解決策であることはわかっていますが、前処理のための適切なライブラリが見つかるまでの一時的な解決策にすぎません.

しかし、興味深い機能について話しましょう。

メンバー グループ

多くの場合、次のようなコードがあります:

class foo
{
public:

 …

 /// \returns A reference to the variable.
 T& get_variable()
 {
 return var_;
 }

 /// \returns A reference to the variable.
 const T& get_variable() const
 {
 return var_;
 }
};

複数の関数は実質的に同じことを行いますが、署名がわずかに異なります。ドキュメントを何度も繰り返すのは非常に面倒です。

メンバー グループを使用すると、次のことを行う必要がなくなります:

class foo
{
public:
 /// \returns A reference to the variable.
 /// \group get_variable
 T& get_variable()
 {
 return var_;
 }

 /// \group get_variable
 const T& get_variable() const
 {
 return var_;
 }
};

37 コマンドはエンティティをメンバー グループに追加します。名前が示すように、これは同じクラス/名前空間/などのメンバーであるエンティティに対してのみ機能します。グループ名はグループの内部識別子にすぎず、グループ内で一意である必要があります

新しいグループ識別子を持つ最初のエンティティは、グループのメイン エンティティです。そのコメントはグループ コメントに使用され、そのタイプはグループに使用されるヘッダーを定義します。グループを使用すると、出力は次のようになります:

関数 41

(1) T& get_variable();

(2) const T& get_variable() const;

返品 :変数への参照。

これは、cppreference.com がドキュメントを作成する方法に似ています。

モジュール

関連エンティティをグループ化する方法として、モジュールも追加しました。56 コマンドはエンティティをモジュールに追加します。それは最大で 1 つのモジュールに含めることができ、すべての子に渡されます。たとえば、名前空間で実行すると、その名前空間内のすべてのエンティティがそのモジュールに追加されます。

モジュールはデフォルトでエンティティのドキュメントに表示されます - 67 で制御できます コマンド - 新しいインデックス ファイル 77 各モジュール内のすべてのエンティティを含むすべてのモジュールを一覧表示します。

プロジェクトに複数の論理コンポーネントがあり、概要を簡単に説明したい場合に便利です。

エンティティ リンクの改善

コメント内には、別のエンティティにリンクするための 2 つの構文があります:

    <リ>

    89 (CommonMark リンクは URL なしでタイトル付き)

    <リ>

    99 (URL なしの CommonMark リンク)

102 参照するエンティティの一意の識別子です。正しい URL は標準語によって入力されます。

ここで、3 番目の構文を追加しました:116 、つまり 127 内の URL を持つ CommonMark リンク protocol.他の 2 つのオプションと同様に、standardese は URL を自動的に入力します。

しかし、そのリンク モデルの問題は、138 が 詳細です:

// unique name is: ns
namespace ns
{
 // unique name is: ns::foo(void*)
 // unique name of param is: ns::foo(void*).param
 void foo(void* param);

 // unique name is: ns::bar<T>
 template <typename T> // unique name of `T` is: ns::bar<T>.T
 struct bar
 {
 // unique name is: ns::bar<T>::f1()
 void f1();
 
 // unique name is: ns::bar<T>::f2()
 void f2();
 };
}

オーバーロードされていない関数の署名は必要ありませんが、一意の名前を 140 で任意の文字列に変更できます コマンド、これはまだ冗長です。たとえば、159 からリンクする場合 165 まで 、次のように入力する必要がありました:178 .

これで、名前検索によるリンク モードが追加されました。固有の名前を 182 で開始するだけです。 または 196 standardese は、通常の C++ の名前検索と同様のルールでエンティティを検索します。そのため、単純に 209 にリンクできます。 218 から 書くことによって:226 .

インライン ドキュメント

一部のエンティティのドキュメントは、デフォルトでインラインで表示されるようになりました。これは、232 のパラメーター、メンバー変数に適用されます。 、列挙値、または基本クラス。以前は、それらを文書化すると、標準化によって新しいセクションが追加され、概要が繰り返されていました。

列挙 244

enum class foo
{
 a,
 b,
 c
};

列挙型。

列挙定数 254

a

値 a.

列挙定数 264

b

値 b.

列挙定数 275

c

値 c.

構造体 282

struct bar
{
 int a;
};

構造体。

変数 290

int a;

いくつかの変数。

関数 302

void func(int a);

関数。

パラメータ 318

int a

パラメータ。

これで、小さなリストでインラインで表示できます:

列挙 320

enum class foo
{
 a,
 b,
 c
};

列挙型。

列挙値:

    <リ>

    330 - 値 a.

    <リ>

    343 - 値 b.

    <リ>

    354 - 値 c.

構造体 364

struct bar
{
 int a;
};

構造体。

メンバー:

  • 373 - いくつかの変数。

関数 388

void func(int a);

関数。

パラメータ:

  • 390 - パラメータ。

その他の改善

小さいものはたくさんあります。

409 を使用してエンティティの概要を完全に制御できるようになりました 実際の概要の代わりに表示される任意の文字列に概要を設定するだけです。以前は、関数の特定のパラメータなどを非表示にすることしかできませんでした。

見出しが改善されました。以前は、エンティティのタイプのみが表示されていました:416423 .特定の署名を検出し、より意味のある意味を与えるようになりました:433447 など

グローバルな 452 によって、マクロの「定義」を概要から隠すことができるようになりました オプション。マクロ定義は実装の詳細であることが多いため、これは便利です。

いくつかの重大な変更もあります:コメントで強制的な改行を行うには、行末で CommonMark バックスラッシュを使用できなくなり、代わりにスラッシュを使用する必要があります (これは技術的な制限です)。コード>463 と 476 リモート コメントのコマンドは、任意の位置ではなく、コメントの先頭にある必要があります。また、関数テンプレートの一意の名前が簡素化されました。テンプレート パラメータをそこに渡してはなりません。

しかし、最大かつ最も強力な機能であるテンプレート モードについて説明しましょう。

テンプレート モード

standardese は基本的なテンプレート言語としても機能するようになりました。ヘッダー ファイルではないファイルを渡すと、それらは前処理されます。これにより、次の 2 つのことが行われます:488 内のすべての URL を正しくリンクする プロトコルと特別なコマンドの置き換え.

これは、例によって最もよく示されます。次の C++ 入力ファイルを考えてみましょう:

/// Struct a.
struct a {};

/// A function.
void func();

/// Struct b.
struct b {};

次のような非ソース ファイル入力:

### A heading

This file is in Markdown format, but you can use *anything* you want.
standardese doesn't care about the format,
it just does dumb text manipulation.

I can link to [the function](standardese://func()/) and it will be resolved.
But I can also show output of standardese here:

{ { standardese_doc_synopsis func() commonmark } }

This line will be replaced with the synopsis of `func()` in the commonmark format.
But it can be more advanced:

{ { standardese_for $entity file.hpp } }
 { { standardese_if $entity name func() } }
 { { standardese_else } }
 * { { standardese_doc_text $entity commonmark } }
 { { standardese_end } }
{ { standardese_end } }

This will show the documentation text of the two structs.

両方のファイルを standardese に渡すと、C++ ファイルの通常のドキュメントが作成され、テンプレート ファイルが次のように前処理されます:

見出し

このファイルは Markdown 形式ですが、何でも使用できます あなたが望む.standardeseはフォーマットを気にせず、愚かなテキスト操作を行うだけです.

関数にリンクできます (手動編集:リンクはここでは明らかに機能しません)。解決されます。ただし、ここで標準語の出力を表示することもできます:

void func();

この行は 492 の概要に置き換えられます CommonMark 形式ですが、さらに高度な場合もあります:

 * Struct a.

 * Struct b.

これにより、2 つの構造体のドキュメント テキストが表示されます。

これは、チュートリアルなどの追加ファイルを書きたい場合に便利です。しかし、505 出力全体をカスタマイズするファイルを渡すことができます。何も渡さない場合、次のように動作します:

{ { standardese_doc $file $format } }

512 現在のファイル 529 を参照します 指定された出力形式に変換します。これにより、各ファイルのドキュメントが標準で行われるようにレンダリングされます。テンプレート構文の概要については、readme を確認してください。

ただし、追加のファイルを使用する場合は、535 が最適です コマンド。549 protocol 生成されたドキュメントの一部にリンクできますが、アンカーコマンドを使用すると、リンクバックできます:

{ { standardese_doc_anchor unique-name <format> } }

これにより、ファイルにアンカーが作成されます。ただし、559 が登録されるので、ドキュメンテーション コメント内のリンク ターゲットとして使用できます!

テンプレート言語は現在非常に基本的なものであり、失敗した場合のエラー メッセージは適切ではありませんが、すでに価値があり、将来的に改善される予定です.

次は?

このリリースでは、標準化は Doxygen のドキュメントを移行する段階にあります.しかし、私はそれに取り組み続けます.私は多くの機能を計画しており、コードだけに基づく自動コメント生成にすでに取り組み始めているかもしれません. .

ライブ デモをご覧になりたい場合は、私の Meeting C++ Lightning Talk をご覧ください。ツールは Github ページから入手できます。詳細については、readme をお読みください。