Skip to content
Merged
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
16 changes: 16 additions & 0 deletions docs/wiki/Code-Writer.md
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,8 @@ Emits:
// This code was generated by ExampleGenerator (version 1.0.0).
// Changes to this file will be lost when the source generator runs again.

#pragma warning disable CS1591

#if !NET48_OR_GREATER && !PURVIEW_TELEMETRY_NON_NULLABLE
#nullable enable
#endif
Expand All @@ -480,6 +482,20 @@ Emits:
namespace Purview.Telemetry;
```

`AutoGeneratedHeader` writes `#pragma warning disable CS1591` by default, so generated public members
do not require XML documentation comments in consuming projects that produce a documentation file.
Passing `CS1591` through the `pragmas` parameter is ignored rather than duplicated. Opt out per writer
or generator-wide:

```csharp
writer.IncludeMissingXmlCommentPragma = false;

var settings = GenerationSettings.Create<MyGenerator>() with
{
IncludeMissingXmlCommentPragma = false,
};
```

The generator version in the header and the `GeneratedCode` attribute comes from the
`GenerationSettings` used to create the writer. When settings are created via
`GenerationSettings.Create<TGenerator>()`, the full assembly informational version is used, so any
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "sourcegenerator-framework",
"version": "1.2.0",
"version": "1.2.1",
"license": "MIT",
"author": {
"name": "Kieron Lanning",
Expand Down
2 changes: 1 addition & 1 deletion src/src/SourceGeneratorFramework/Sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ See [`SourceGeneratorFramework.ExampleGenerator`](../SourceGeneratorFramework.Ex

## Generated attributes and determinism

`CodeWriter` automatically stamps generated declarations with `[GeneratedCode]`, `[CompilerGenerated]`, and `[ExcludeFromCodeCoverage]` (where applicable) using the generator identity supplied to its constructor. The header written by `AutoGeneratedHeader()` is deterministic and does not include a timestamp, so the same inputs always produce the same source.
`CodeWriter` automatically stamps generated declarations with `[GeneratedCode]`, `[CompilerGenerated]`, and `[ExcludeFromCodeCoverage]` (where applicable) using the generator identity supplied to its constructor. The header written by `AutoGeneratedHeader()` is deterministic and does not include a timestamp, so the same inputs always produce the same source. It also writes `#pragma warning disable CS1591` by default, so generated public members do not require XML documentation comments in consuming projects that produce a documentation file; set `CodeWriter.IncludeMissingXmlCommentPragma` or `GenerationSettings.IncludeMissingXmlCommentPragma` to `false` to omit it.

### The `#nullable enable` directive

Expand Down
38 changes: 35 additions & 3 deletions src/src/SourceGeneratorShared/CodeWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public sealed partial class CodeWriter
const int DefaultExpressionCapacity = 128;
const int DefaultIndentationSize = 4;
const int DefaultMaximumLineLength = 100;
const string MissingXmlCommentWarning = "CS1591";

int _indentLevel;
int _nextScopeId;
Expand Down Expand Up @@ -82,6 +83,7 @@ public CodeWriter(
GeneratorVersion = settings.GeneratorVersion;
NullableDirectiveMode = settings.NullableDirectiveMode;
IsNullableContextEnabled = settings.IsNullableContextEnabled;
IncludeMissingXmlCommentPragma = settings.IncludeMissingXmlCommentPragma;
ThrowOnUnclosedScopes = throwOnUnclosedScopes;

DefaultTypeAccessibility = settings.DefaultTypeAccessibility;
Expand Down Expand Up @@ -115,6 +117,7 @@ public CodeWriter(
GeneratorVersion = source.GeneratorVersion;
NullableDirectiveMode = source.NullableDirectiveMode;
IsNullableContextEnabled = source.IsNullableContextEnabled;
IncludeMissingXmlCommentPragma = source.IncludeMissingXmlCommentPragma;
ThrowOnUnclosedScopes = source.ThrowOnUnclosedScopes;
DefaultIncludeGeneratedAttributes = source.DefaultIncludeGeneratedAttributes;
DefaultTypeAccessibility = source.DefaultTypeAccessibility;
Expand Down Expand Up @@ -185,6 +188,14 @@ public CodeWriter(
/// </remarks>
public bool? IsNullableContextEnabled { get; set; }

/// <summary>
/// Gets or sets whether <see cref="AutoGeneratedHeader"/> disables <c>CS1591</c>, so that generated
/// public members do not require XML documentation comments. The value is seeded from
/// <see cref="GenerationSettings.IncludeMissingXmlCommentPragma"/> at construction and defaults to
/// <see langword="true"/>.
/// </summary>
public bool IncludeMissingXmlCommentPragma { get; set; } = true;

/// <summary>
/// Gets or sets whether generated attributes are emitted for declarations that do not
/// explicitly override <see cref="TypeDeclarationOptions.IncludeGeneratedAttributes"/>,
Expand Down Expand Up @@ -2088,14 +2099,24 @@ public CodeWriter Constructor(ConstructorDeclarationOptions declaration, Action<
/// <summary>
/// Writes the standard header for an automatically generated source file.
/// </summary>
/// <remarks>
/// The header disables <c>CS1591</c> so that generated public members do not require XML
/// documentation comments in consuming projects that produce a documentation file. Set
/// <see cref="IncludeMissingXmlCommentPragma"/> (or
/// <see cref="GenerationSettings.IncludeMissingXmlCommentPragma"/>) to <see langword="false"/> to
/// omit it.
/// </remarks>
/// <param name="generatorName">The generator name; defaults to <see cref="GeneratorName"/>.</param>
/// <param name="version">The generator version; defaults to <see cref="GeneratorVersion"/>.</param>
/// <param name="nullableDirective">
/// Controls whether the <c>#nullable enable</c> directive is emitted and whether nullable
/// reference annotations are rendered. When <see langword="null"/>, <see cref="NullableDirectiveMode"/>
/// is used, which defaults to <see cref="NullableDirectiveMode.Auto"/>.
/// </param>
/// <param name="pragmas">The pragmas to include in the header.</param>
/// <param name="pragmas">
/// Additional pragmas to include in the header; <c>CS1591</c> is ignored here when
/// <see cref="IncludeMissingXmlCommentPragma"/> already writes it.
/// </param>
/// <returns>The current writer.</returns>
/// <example>
/// <code>writer.AutoGeneratedHeader(pragmas: ["CS0618"]);</code>
Expand Down Expand Up @@ -2128,11 +2149,22 @@ params string[] pragmas
if (ShouldWriteNullableDirective(mode, IsNullableContextEnabled))
NewLine().Line("#nullable enable");

if (pragmas is not null && pragmas.Length > 0)
var additionalPragmas = pragmas ?? [];
if (IncludeMissingXmlCommentPragma || additionalPragmas.Length > 0)
{
NewLine();
foreach (var pragma in pragmas)

if (IncludeMissingXmlCommentPragma)
Write("#pragma warning disable ").Line(MissingXmlCommentWarning);

foreach (var pragma in additionalPragmas)
{
if (
IncludeMissingXmlCommentPragma
&& string.Equals(pragma, MissingXmlCommentWarning, StringComparison.Ordinal)
)
continue;

Write("#pragma warning disable ").Line(pragma);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/src/SourceGeneratorShared/GenerationSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ public GenerationSettings(
/// </summary>
public bool? IsNullableContextEnabled { get; init; }

/// <summary>
/// Gets whether the header written by <c>CodeWriter.AutoGeneratedHeader</c> disables <c>CS1591</c>,
/// so that generated public members do not require XML documentation comments. The default is
/// <see langword="true"/>.
/// </summary>
public bool IncludeMissingXmlCommentPragma { get; init; } = true;

/// <summary>
/// Gets whether created code writers validate undisposed scopes.
/// </summary>
Expand Down
74 changes: 74 additions & 0 deletions src/tests/SourceGeneratorShared.UnitTests/CodeWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2591,6 +2591,74 @@ public async Task AutoGeneratedHeader_WritesHeader()
await Assert.That(result).DoesNotContain("// Generated at ");
}

[Test]
public async Task AutoGeneratedHeader_GivenAdditionalPragmas_WritesMissingXmlCommentPragmaOnce()
{
var writer = CodeWriterFactory.ForTests();

writer.AutoGeneratedHeader("TestGenerator", "1.0", NullableDirectiveMode.Disable, "CS0618", "CS1591");

await Assert
.That(writer.ToString())
.IsEqualTo(
"// <auto-generated />\n"
+ "// This code was generated by TestGenerator (version 1.0).\n"
+ "// Changes to this file will be lost when the source generator runs again.\n"
+ "\n"
+ "#pragma warning disable CS1591\n"
+ "#pragma warning disable CS0618\n"
+ "\n"
);
}

[Test]
public async Task AutoGeneratedHeader_GivenMissingXmlCommentPragmaDisabled_OmitsPragma()
{
var writer = CodeWriterFactory.ForTests(
settings: new GenerationSettings("TestGenerator", "1.0.0")
{
NullableDirectiveMode = NullableDirectiveMode.Disable,
IncludeMissingXmlCommentPragma = false,
}
);

writer.AutoGeneratedHeader("TestGenerator", "1.0");

await Assert
.That(writer.ToString())
.IsEqualTo(
"// <auto-generated />\n"
+ "// This code was generated by TestGenerator (version 1.0).\n"
+ "// Changes to this file will be lost when the source generator runs again.\n"
+ "\n"
);
}

[Test]
public async Task AutoGeneratedHeader_GivenMissingXmlCommentPragmaDisabledAndExplicitPragma_WritesPragma()
{
var writer = CodeWriterFactory.ForTests(
settings: new GenerationSettings("TestGenerator", "1.0.0")
{
NullableDirectiveMode = NullableDirectiveMode.Disable,
IncludeMissingXmlCommentPragma = false,
}
);

writer.AutoGeneratedHeader("TestGenerator", "1.0", pragmas: ["CS1591"]);

await Assert
.That(writer.ToString())
.IsEqualTo(
"// <auto-generated />\n"
+ "// This code was generated by TestGenerator (version 1.0).\n"
+ "// Changes to this file will be lost when the source generator runs again.\n"
+ "\n"
+ "#pragma warning disable CS1591\n"
+ "\n"
);
}

[Test]
public async Task AutoGeneratedHeader_GivenDefaultSettings_WritesNullableEnableDirective()
{
Expand Down Expand Up @@ -2689,6 +2757,8 @@ await Assert
+ "// This code was generated by TestGenerator (version 1.0).\n"
+ "// Changes to this file will be lost when the source generator runs again.\n"
+ "\n"
+ "#pragma warning disable CS1591\n"
+ "\n"
);
}

Expand All @@ -2713,6 +2783,8 @@ await Assert
+ "\n"
+ "#nullable enable\n"
+ "\n"
+ "#pragma warning disable CS1591\n"
+ "\n"
);
}

Expand Down Expand Up @@ -5688,6 +5760,8 @@ await Assert
+ "// This code was generated by TestGenerator (version 1.0.0).\n"
+ "// Changes to this file will be lost when the source generator runs again.\n"
+ "\n"
+ "#pragma warning disable CS1591\n"
+ "\n"
+ "#if !NET48_OR_GREATER && !PURVIEW_TELEMETRY_NON_NULLABLE\n"
+ "#nullable enable\n"
+ "#endif\n"
Expand Down
Loading