Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),

### [Unreleased]

#### Added

- **Configurable IL substring normalization** — Added `ShouldILNormalizeContainingConfiguredStrings` and `ILNormalizeContainingStrings`. When enabled, every occurrence of each configured substring is replaced with `<nildiff:normalized:configured-value>`, while all surrounding text on the same IL line remains comparable. Both configured normalization and configured line exclusion apply across every IL instruction context, including program string literals loaded by `ldstr`. Leading and trailing whitespace in non-empty normalization values remains part of the exact match; whitespace-only values are ignored. This is intentionally separate from `ILIgnoreLineContainingStrings`, which continues to remove an entire matching line from comparison. Creator mode enables configured substring normalization automatically. Normalization values shorter than four characters now produce the same console/report safety warning class as short ignore values, with wording specific to the risk of normalizing legitimate IL content.
- **Auditable configured IL transformations** — When audit logging is enabled, compared assemblies with effective configured ignore or normalization rules now include `ilTransformations.old` and `ilTransformations.new` evidence. Every effective rule records exactly four fields: its operation-specific application-index `ruleId`, `operation`, configured `pattern`, and `appliedLineCount`; zero-match rules remain visible. The count is the number of raw IL lines to which the rule was applied, with multiple matches on one line counted once. The rule-ID numeric suffix uses four digits as its minimum width and expands for indices above 9999. Ignore-rule evidence is collected before normalization, matching comparison behavior, and uses the same record shape as configured normalization evidence. With IL text output enabled, counts are collected in the existing loop that materializes filtered IL for writing. With IL text output disabled, a separate non-retaining audit pass adds CPU work but preserves the streaming comparison memory profile apart from bounded per-file rule summaries.
- **Real disassembler IL corpus** — Added reproducible source and pinned golden IL from `dotnet-ildasm 0.12.2.0` and `ilspycmd 9.1.0.7988`, the fallback baseline for inspecting assemblies targeting .NET 8/9/10. The signed test assembly covers ordinary classes and multiple methods, instance/static constructors, async and iterator state machines, lambdas and compiler-generated types, generic types and methods, properties, events, fields, signed AssemblyRefs, and reproducible COM interop metadata. A clearly identified test-only strong-name key keeps the sample assembly and public key token reproducible. ActiveX wrapper output is documented but excluded because portable `aximp` tooling and reproducible input are not available in the cross-platform .NET SDK. Corpus regeneration requires PowerShell 7 (`pwsh`).

#### Changed

- **Class-internal IL member ordering is compared hierarchically** — Order-independent IL comparison now decomposes classes into member blocks and matches each block by parent class path, member signature, and content hash. Reordering methods within the same class no longer produces a false mismatch, while method body changes, swapping bodies between different methods, and moving methods between classes remain differences. Regression tests cover realistic `dotnet-ildasm` and `ilspycmd` class/method layouts.
- **Build-variant IL values are normalized instead of discarded** — MVID, method RVA, code-size, and WinForms `AxHost.TypeLibraryTimeStampAttribute` values are now replaced with rule-specific stable markers in every mode. Each matching line prefix is preserved while the build-variant portion that follows it is replaced. For ILSpy's multiline type-library timestamp form, the complete byte blob through its closing `)` is collapsed into one marker. Built-in rules cover the actual comment and custom-attribute forms emitted by both supported disassemblers, including ILSpy's custom-attribute syntax without dotnet-ildasm's `class ` token, and are applied to every IL text regardless of which disassembler produced it; the disassembler recorded in reports identifies pattern provenance only. Normalization still occurs after IL cache retrieval, with no cache format or key change, so compatible existing cache entries remain reusable.
- **Creator defaults preserve more meaningful differences** — Renamed the built-in profile from `buildserver-winforms` to `creator-default`. Its predefined build-server/path substrings now populate `ILNormalizeContainingStrings` instead of `ILIgnoreLineContainingStrings`, preserving non-variant content on matching lines. Creator-profile values form the baseline and are applied first in profile order; user-configured values follow in their configured array order. The `.publickeytoken = (` suppression entry was removed and is not replaced by normalization, so AssemblyRef public key token changes remain visible in creator mode.
- **Normalization reporting and tool guidance are more explicit** — Markdown and HTML reports show built-in normalization rules, configured normalization substrings, and configured ignore substrings in that order. Built-in and configured-normalization tables state that their row order is the application order. The tables distinguish `Line Prefix Pattern`, `Substring to Normalize`, and `Substring to Ignore`; configured values are displayed without decorative quotes, while an enabled setting with no effective values is reported without rendering an empty table. The built-in table also shows each pattern's replacement marker and observed disassembler. Duplicate and containment-related normalization values now produce console/report warnings, including relationships that arise after creator-profile values are prepended to configured values. Guidance clarifies sequential replacement order, why the current built-in and creator rules are order-independent, that `nildiff` itself targets `net8.0`, and that `ilspycmd 9.1.0.7988` is pinned as the fallback baseline for inspecting assemblies targeting .NET 8/9/10. English/Japanese configuration documentation, schema, guides, and report samples are aligned with the new behavior.

#### Removed

- **`ShouldIgnoreMVID` configuration setting** — Removed as a breaking configuration change. MVID values are now always normalized to `<nildiff:normalized:mvid>` instead of conditionally removing or comparing the complete MVID line.

### [1.24.0] - 2026-07-29

#### Added
Expand Down Expand Up @@ -1719,6 +1736,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),

### [Unreleased]

#### 追加

- **設定可能な IL 部分文字列正規化** — `ShouldILNormalizeContainingConfiguredStrings` と `ILNormalizeContainingStrings` を追加しました。有効時は、設定した各部分文字列のすべての出現箇所を `<nildiff:normalized:configured-value>` へ置換し、同じIL行にある周辺テキストは比較可能な状態で残します。設定正規化と設定行除外はどちらも、`ldstr` が読み込むプログラム文字列リテラルを含む、すべての IL 命令文脈へ適用します。空でない正規化値の前後空白は正確な一致条件の一部として保持し、空白だけの値は無視します。これは、一致した行全体を比較から除外する従来の `ILIgnoreLineContainingStrings` とは独立した機能です。creatorモードでは設定文字列の正規化を自動的に有効化します。4文字未満の正規化値は、短い無視値と同じコンソール/レポート安全性警告の対象とし、正規のIL内容まで正規化するリスクが分かる文言で表示します。
- **設定 IL 変換の監査証跡** — 監査ログが有効な場合、実効設定除外規則または正規化規則を持つ比較対象Assemblyへ `ilTransformations.old` / `ilTransformations.new` の証跡を追加しました。各実効規則には、操作別の適用位置を表す `ruleId`、`operation`、設定 `pattern`、`appliedLineCount` の4項目だけを記録し、一致数0の規則も残します。適用件数は規則を適用したraw IL行数であり、同一行の複数一致は1件と数えます。規則IDの数値部は4桁を最小幅とし、9999を超える位置では5桁以上へ拡張します。除外規則の証跡は比較動作と同じく正規化より先に収集し、設定正規化の証跡と同じレコード形式で出力します。ILテキスト出力が有効な場合は、書き出し用フィルタ済みILを実体化する既存ループ内で件数も集計します。無効な場合は、本文を保持しない監査用走査のCPUコストが増えますが、ファイル単位の規則サマリー以外は従来のストリーミング比較と同じメモリ特性を維持します。
- **実逆アセンブラ IL コーパス** — 再生成可能なソースと、`dotnet-ildasm 0.12.2.0` および.NET 8/9/10をtarget frameworkとするAssemblyを調査するfallback baselineである `ilspycmd 9.1.0.7988` から取得したgolden ILを追加しました。署名済みテストAssemblyは、通常classと複数method、instance/static constructor、async/iterator state machine、lambda/compiler-generated type、generic type/method、property/event/field、署名済みAssemblyRef、再現可能なCOM interop metadataを網羅します。用途を明記したテスト専用strong-name鍵により、サンプルAssemblyとpublic key tokenの再現性を維持します。ActiveX wrapper出力は、cross-platform .NET SDKでportableな `aximp` ツールと再現可能な入力を用意できないため、除外理由のみ文書化しています。コーパス再生成にはPowerShell 7(`pwsh`)が必要です。

#### 変更

- **class内ILメンバー順を階層付きで比較** — 順序非依存IL比較では、classをmemberブロックへ分解し、親classパス、memberシグネチャ、内容ハッシュの組み合わせで照合するようにしました。同じclass内でmethod順だけが変わっても誤った差分になりません。一方、method本体の変更、異なるmethod間での本体入れ替え、別classへのmethod移動は引き続き差分になります。実際的な `dotnet-ildasm` と `ilspycmd` のclass/method配置を回帰テストで網羅しています。
- **ビルド依存 IL 値を破棄せず正規化** — MVID、method RVA、code-size、WinFormsの `AxHost.TypeLibraryTimeStampAttribute` 値を、全モードで規則別の安定したマーカーへ置換するようにしました。照合した行接頭辞は保持し、それに続くビルド依存部分だけを置換します。ILSpyの複数行type-library timestamp形式では、閉じ `)` までのbyte blob全体を1個のマーカーへ縮約します。組み込み規則は、ILSpyのcustom attribute構文がdotnet-ildasmの `class ` tokenを含まない違いも含め、両対応逆アセンブラが実際に出力するコメント/custom attribute形式を網羅し、生成元の逆アセンブラに関係なくすべてのIL textへ適用します。レポート上の逆アセンブラ名はパターンの由来を示すだけです。正規化は従来どおりILキャッシュ取得後に行い、キャッシュ形式とキーは変更していないため、互換性のある既存キャッシュエントリは引き続き利用できます。
- **creator既定値で意味のある差分をより多く保持** — 組み込みプロファイル名を `buildserver-winforms` から `creator-default` へ変更しました。既定のbuild-server/path部分文字列は `ILIgnoreLineContainingStrings` ではなく `ILNormalizeContainingStrings` へ設定し、一致行にあるビルド依存でない内容を保持します。creatorプロファイル値を基盤としてプロファイル内の順序で先に適用し、その後にユーザー設定値を設定配列順で適用します。`.publickeytoken = (` の抑制エントリは削除し、正規化対象にもしていないため、AssemblyRefのpublic key token変更はcreatorモードでも差分として残ります。
- **正規化レポートとツール案内を明確化** — Markdown/HTMLレポートには、組み込み正規化規則、設定正規化部分文字列、設定無視部分文字列の順で表示します。組み込み表と設定正規化表には、行の並びが適用順であることを明記します。表では `Line Prefix Pattern`、`Substring to Normalize`、`Substring to Ignore` を区別し、設定値へ装飾的なダブルクオートを付けません。有効だが実効値が0件の場合は空の表を出さず、設定値がないことだけを明示します。組み込み表には各パターンの置換マーカーと確認元逆アセンブラも表示します。重複または包含関係にある正規化値は、creatorプロファイル値を設定値より前へ追加した結果生じた関係も含めてコンソール/レポート警告の対象にしました。逐次置換の適用順、現行の組み込み規則とcreator規則で順序が結果へ影響しない理由、`nildiff` 本体が `net8.0` をtargetとすること、`ilspycmd 9.1.0.7988` を.NET 8/9/10をtarget frameworkとするAssembly調査の固定fallback baselineとすることを案内に明記しました。英日両方の設定文書、schema、guide、レポートサンプルを新しい挙動へ揃えました。

#### 削除

- **`ShouldIgnoreMVID` 設定** — 破壊的な設定変更として削除しました。MVID値は、完全なMVID行を条件付きで除外または比較するのではなく、常に `<nildiff:normalized:mvid>` へ正規化します。

### [1.24.0] - 2026-07-29

#### 追加
Expand Down
43 changes: 41 additions & 2 deletions Common/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ public static class Constants
/// <summary>Name of the ILSpy command-line tool. / ILSpy コマンドラインツールの名前。</summary>
public const string ILSPY_CMD = "ilspycmd";

/// <summary>Supported ilspycmd version. / サポート対象の ilspycmd バージョン。</summary>
public const string ILSPY_CMD_VERSION = "9.1.0.7988";

/// <summary>Error message for invalid parallelism values. / 不正な並列度の値に対するエラーメッセージ。</summary>
public const string ERROR_MAX_PARALLEL = "The maximum degree of parallelism must be 1 or greater.";

Expand Down Expand Up @@ -89,13 +92,49 @@ public static class Constants
public const int IL_CACHE_TIME_TO_LIVE_DEFAULT_HOURS = 12;

/// <summary>
/// Line prefix used to identify and exclude MVID lines from IL output during comparison.
/// Line prefix used to identify MVID values for normalization during IL comparison.
/// MVID (Module Version ID) is metadata that can change on every rebuild and does not
/// represent a meaningful IL difference.
/// IL 出力から比較時に除外する MVID 行の接頭辞
/// IL 比較時に正規化する MVID 値を識別するための行接頭辞
/// MVID は再ビルドごとに変わり得る Module Version ID メタデータで、実行される IL 差分を直接意味しない。
/// </summary>
public const string IL_MVID_LINE_PREFIX = "// MVID:";

/// <summary>
/// dotnet-ildasm line prefix used to identify RVA values for normalization during IL comparison.
/// IL 比較時に正規化する dotnet-ildasm の RVA 値を識別するための行接頭辞。
/// </summary>
public const string IL_RVA_LINE_PREFIX = "// Method begins at Relative Virtual Address (RVA) 0x";

/// <summary>
/// ilspycmd line prefix used to identify RVA values for normalization during IL comparison.
/// IL 比較時に正規化する ilspycmd の RVA 値を識別するための行接頭辞。
/// </summary>
public const string IL_ILSPY_RVA_LINE_PREFIX = "// Method begins at RVA 0x";

/// <summary>
/// dotnet-ildasm line prefix used to identify code-size values for normalization during IL comparison.
/// IL 比較時に正規化する dotnet-ildasm のコードサイズ値を識別するための行接頭辞。
/// </summary>
public const string IL_CODE_SIZE_LINE_PREFIX = "// Code size ";

/// <summary>
/// ilspycmd line prefix used to identify code-size values for normalization during IL comparison.
/// IL 比較時に正規化する ilspycmd のコードサイズ値を識別するための行接頭辞。
/// </summary>
public const string IL_ILSPY_CODE_SIZE_LINE_PREFIX = "// Code size: ";

/// <summary>
/// dotnet-ildasm line prefix used to identify WinForms type-library timestamps for normalization during IL comparison.
/// IL 比較時に正規化する dotnet-ildasm の WinForms タイプライブラリタイムスタンプを識別するための行接頭辞。
/// </summary>
public const string IL_TYPE_LIBRARY_TIMESTAMP_LINE_PREFIX = ".custom instance void class [System.Windows.Forms]System.Windows.Forms.AxHost/TypeLibraryTimeStampAttribute::.ctor(string) = ( ";

/// <summary>
/// ilspycmd line prefix used to identify WinForms type-library timestamps for normalization during IL comparison.
/// IL 比較時に正規化する ilspycmd の WinForms タイプライブラリタイムスタンプを識別するための行接頭辞。
/// </summary>
public const string IL_ILSPY_TYPE_LIBRARY_TIMESTAMP_LINE_PREFIX = ".custom instance void [System.Windows.Forms]System.Windows.Forms.AxHost/TypeLibraryTimeStampAttribute::.ctor(string) = (";

}
}
Loading
Loading