Skip to content

Commit d45cbb3

Browse files
ericstjCopilot
andauthored
Platform specific docs analyzer (#128411)
## Add PlatformDocAnalyzer to enforce consistent documentation across platform-specific builds When a library uses `UseCompilerGeneratedDocXmlFile=true` (the default) and targets platform-specific TFMs like `net11.0-windows`, only one platform's compiler-generated doc XML is shipped to customers in the IntelliSense package. If XML doc comments are placed on platform-specific partial source files, they may be missing or inconsistent on other platforms. This PR adds a Roslyn analyzer (`eng/analyzers/PlatformDocAnalyzer`) that enforces documentation placement conventions and validates doc consistency. It only activates for platform-specific TFMs with `UseCompilerGeneratedDocXmlFile=true`. ### Diagnostics | ID | Severity | Description | |----|----------|-------------| | PLATDOC001 | Warning | Public type has no source file named `TypeName.cs`. | | PLATDOC002 | Warning | Partial source file doesn't follow the `TypeName.Something.cs` naming convention. | | PLATDOC003 | Warning | Public member in a non-primary partial file has XML doc comments that should be moved to `TypeName.cs`. | | PLATDOC004 | Warning | Documentation for a public API differs from the canonical (platform-agnostic) build. | PLATDOC001–003 are heuristic rules that guide source organization for partial types split across multiple files. PLATDOC004 is the authoritative check: when a project also targets a platform-agnostic TFM (e.g. `net11.0` alongside `net11.0-windows`), the build locates the canonical TFM's compiler-generated doc XML and passes it to the analyzer as an `AdditionalFile`. The analyzer then compares each public API's documentation against the canonical version and reports mismatches. ### Build integration - **`eng/intellisense.targets`** — For platform-specific TFMs, derives the canonical TFM by stripping the platform suffix (e.g. `net11.0-windows` → `net11.0`) and passes its doc XML as an `AdditionalFile` if available. Uses the artifact path directly rather than a `ProjectReference` to avoid circular dependencies with PNSE builds. - **`eng/generators.targets`** — Wires the analyzer into all `IsSourceProject` C# builds. - **`eng/analyzers/PlatformDocAnalyzer/PlatformDocAnalyzer.props`** — Declares `CompilerVisibleProperty` and `CompilerVisibleItemMetadata` for the analyzer to read MSBuild context. ### Suppressions Added `#pragma warning disable` in 5 System.Private.Xml files that use established non-platform-specific patterns (`TypeNameAsync.cs` for async partials, `XmlResolver.FileSystemResolver.cs` / `ThrowingResolver.cs` for nested-type-adjacent properties). --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 444d544 commit d45cbb3

15 files changed

Lines changed: 1141 additions & 50 deletions

docs/coding-guidelines/adding-api-guidelines.md

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,48 @@ The rest of the documentation workflow depends on whether the assembly has the `
5858
- Triple-slash comments in source code are synced to dotnet-api-docs periodically (every preview).
5959
- More recently introduced libraries typically follow this workflow.
6060

61+
### Documentation placement in platform-specific libraries
62+
63+
When a library targets platform-specific frameworks (e.g. `net11.0-windows`, `net11.0-linux`),
64+
only **one** platform's compiler-generated doc XML is selected as the source of truth and shipped
65+
to all customers in the IntelliSense package. This means that if XML doc comments for a public API
66+
appear only in a platform-specific partial file, they may be missing from the shipped docs on other
67+
platforms.
68+
69+
To ensure consistent documentation across all platforms, follow these rules:
70+
71+
1. **Place docs on the primary source file.** Each public type should have a primary source file
72+
named `TypeName.cs`. All public API documentation (`/// <summary>`, `/// <param>`, etc.) must
73+
be placed in this file.
74+
2. **Follow the naming convention for partial files.** Platform-specific or feature-specific
75+
partials must follow the `TypeName.Something.cs` naming convention (e.g. `Socket.Windows.cs`,
76+
`Socket.Unix.cs`).
77+
3. **Do not add public XML doc comments in non-primary partial files.** If a public member is
78+
declared in a file like `TypeName.Windows.cs`, its documentation should be in `TypeName.cs`
79+
(using a partial method declaration or `<inheritdoc/>`), not in the platform-specific file.
80+
81+
These rules are enforced by the **PlatformDocAnalyzer** (`eng/analyzers/PlatformDocAnalyzer`),
82+
which is automatically applied to all library source projects. The analyzer only activates when
83+
building a platform-specific target framework with `UseCompilerGeneratedDocXmlFile=true`, and
84+
produces the following diagnostics:
85+
86+
| Diagnostic | Description |
87+
|------------|-------------|
88+
| PLATDOC001 | Public type has no source file named `TypeName.cs`. |
89+
| PLATDOC002 | Partial source file doesn't follow the `TypeName.Something.cs` naming convention. |
90+
| PLATDOC003 | Public member in a non-primary partial file has XML documentation that should be moved to `TypeName.cs`. |
91+
| PLATDOC004 | Documentation for a public API differs from the canonical (platform-agnostic) build. |
92+
93+
PLATDOC001–003 are heuristic rules that guide source organization. PLATDOC004 is an authoritative
94+
check: when a project also targets a platform-agnostic TFM (e.g. `net11.0` alongside
95+
`net11.0-windows`), the build passes the canonical TFM's compiler-generated doc XML to the
96+
analyzer, which compares each public API's documentation against it. Any mismatch indicates that
97+
docs were placed on platform-specific source and will be inconsistent across platforms.
98+
99+
If a file legitimately doesn't follow these conventions (e.g. an `Async` partial using the
100+
established `TypeNameAsync.cs` pattern), suppress the specific diagnostic with
101+
`#pragma warning disable PLATDOCnnn` and a brief comment explaining why.
102+
61103
**For libraries with `<UseCompilerGeneratedDocXmlFile>false</UseCompilerGeneratedDocXmlFile>`:**
62104
- The [dotnet-api-docs](https://github.com/dotnet/dotnet-api-docs) repo is the source of truth for documentation.
63105
- Triple-slash comments in source code are synced to dotnet-api-docs **only once** for newly introduced APIs. After the initial sync, all subsequent documentation
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project>
2+
<PropertyGroup>
3+
<!-- Analyzer/generator projects are not source projects. -->
4+
<IsGeneratorProject>true</IsGeneratorProject>
5+
</PropertyGroup>
6+
7+
<Import Project="..\..\Directory.Build.props" />
8+
</Project>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>$(NetCoreAppCurrent)</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(MicrosoftCodeAnalysisVersion)" />
9+
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing" Version="$(CompilerPlatformTestingVersion)" />
10+
</ItemGroup>
11+
12+
<ItemGroup>
13+
<ProjectReference Include="..\PlatformDocAnalyzer\PlatformDocAnalyzer.csproj" />
14+
</ItemGroup>
15+
16+
</Project>

0 commit comments

Comments
 (0)