Browse Source

Document the two roles of the language version in the settings API

The language version appears in two places that share a name but not a
concept, which repeatedly reads as one confused API: on
DecompilerSettings it is a construction shortcut (SetLanguageVersion
initializes the feature flags once and the version is not stored, so
the flags are the only state and the call is deliberately one-way),
while on WholeProjectDecompiler it is an export parameter (the
LangVersion stamped into the project file, defaulting to
GetMinimumRequiredVersion() and rejected below it as a safety net
against exporting uncompilable projects). Spell both roles out in the
XML docs so the distinction no longer has to be reverse-engineered.

Assisted-by: Claude:claude-fable-5:Claude Code
pull/3970/head
Siegfried Pammer 1 month ago
parent
commit
590793fd21
  1. 13
      ICSharpCode.Decompiler.Generators/DecompilerSettingsGenerator.cs
  2. 7
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
  3. 19
      ICSharpCode.Decompiler/DecompilerSettings.cs

13
ICSharpCode.Decompiler.Generators/DecompilerSettingsGenerator.cs

@ -332,12 +332,12 @@ namespace ICSharpCode.Decompiler @@ -332,12 +332,12 @@ namespace ICSharpCode.Decompiler
context.AddSource(hintName, SourceText.From(builder.ToString().Replace("\r\n", "\n"), Encoding.UTF8));
}
// Emitted as partial implementing declarations: the containing class supplies the defining
// stubs, which is where the XML documentation lives (the docs on a partial method's defining
// declaration apply as long as the implementation carries none).
static void WriteSetLanguageVersion(StringBuilder builder, IGrouping<int, SettingInfo>[] versionBuckets)
{
builder.AppendLine("\t\t/// <summary>");
builder.AppendLine("\t\t/// Deactivates all language features from versions newer than <paramref name=\"languageVersion\"/>.");
builder.AppendLine("\t\t/// </summary>");
builder.AppendLine("\t\tpublic void SetLanguageVersion(global::ICSharpCode.Decompiler.CSharp.LanguageVersion languageVersion)");
builder.AppendLine("\t\tpublic partial void SetLanguageVersion(global::ICSharpCode.Decompiler.CSharp.LanguageVersion languageVersion)");
builder.AppendLine("\t\t{");
builder.AppendLine("\t\t\t// By default, all decompiler features are enabled.");
builder.AppendLine("\t\t\t// Disable some of them based on language version:");
@ -356,10 +356,7 @@ namespace ICSharpCode.Decompiler @@ -356,10 +356,7 @@ namespace ICSharpCode.Decompiler
static void WriteGetMinimumRequiredVersion(StringBuilder builder, IGrouping<int, SettingInfo>[] versionBuckets)
{
builder.AppendLine("\t\t/// <summary>");
builder.AppendLine("\t\t/// Gets the lowest language version that includes all currently enabled language features.");
builder.AppendLine("\t\t/// </summary>");
builder.AppendLine("\t\tpublic global::ICSharpCode.Decompiler.CSharp.LanguageVersion GetMinimumRequiredVersion()");
builder.AppendLine("\t\tpublic partial global::ICSharpCode.Decompiler.CSharp.LanguageVersion GetMinimumRequiredVersion()");
builder.AppendLine("\t\t{");
foreach (var bucket in versionBuckets.Reverse())
{

7
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs

@ -60,6 +60,13 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler @@ -60,6 +60,13 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
LanguageVersion? languageVersion;
/// <summary>
/// The C# language version written into the exported project file as LangVersion.
/// This is an export parameter, not decompiler state: when not set explicitly, it defaults
/// to <see cref="DecompilerSettings.GetMinimumRequiredVersion"/> of the current settings,
/// and an explicit value below that minimum is rejected (here and again when the export
/// starts) because the emitted code could not compile under it.
/// </summary>
public LanguageVersion LanguageVersion {
get { return languageVersion ?? Settings.GetMinimumRequiredVersion(); }
set {

19
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -44,12 +44,31 @@ namespace ICSharpCode.Decompiler @@ -44,12 +44,31 @@ namespace ICSharpCode.Decompiler
/// This does not imply that the resulting code strictly uses only language features from
/// that version. Language constructs like generics or ref locals cannot be removed from
/// the compiled code.
/// The language version is a construction shortcut, not state: it initializes the feature
/// flags once (see <see cref="SetLanguageVersion"/>) and is not stored afterwards.
/// </remarks>
public DecompilerSettings(CSharp.LanguageVersion languageVersion)
{
SetLanguageVersion(languageVersion);
}
/// <summary>
/// One-shot profile initializer: deactivates all language features from versions newer than
/// <paramref name="languageVersion"/>. The version itself is not stored - the feature flags
/// are the only state - so the call is not reversible and a later call with a higher version
/// does not re-enable features. Use <see cref="GetMinimumRequiredVersion"/> to derive a
/// version back from the flags.
/// </summary>
public partial void SetLanguageVersion(CSharp.LanguageVersion languageVersion);
/// <summary>
/// Derives the lowest language version that includes all currently enabled language
/// features. The settings do not store a language version, so this derivation is how a
/// version is recovered from the flags; project export uses it as the default (and lower
/// bound) for the LangVersion written into the project file.
/// </summary>
public partial CSharp.LanguageVersion GetMinimumRequiredVersion();
/// <summary>
/// Use C# 9 <c>nint</c>/<c>nuint</c> types.
/// </summary>

Loading…
Cancel
Save