Skip to content

Fix api_list generation gaps - #592

Merged
SimonCropp merged 1 commit into
mainfrom
api-list-fixes
Sep 10, 2026
Merged

Fix api_list generation gaps#592
SimonCropp merged 1 commit into
mainfrom
api-list-fixes

Conversation

@SimonCropp

Copy link
Copy Markdown
Owner

Five defects in the api_list generator, all of which caused shipping APIs to be missing or mis-described.

FeatureUnsafe was not a known symbol

Identifiers.sharedIdentifiers listed every feature constant except FeatureUnsafe, so InterlockedPolyfill.cs (guarded #if !NET11_0_OR_GREATER && FeatureUnsafe && FeatureMemory) parsed to nothing under every moniker. Interlocked.And and Interlocked.Or were absent and #### Interlocked was an empty section header. The same list is duplicated in CountApisForSplitFramework, so the per-framework counts under-counted them too.

Properties rendered without their type

WriteSignature(Property) wrote only the identifier, so an entry read `HoursPerDay` where a method reads `TimeSpan FromDays(int, int)`. Now `long HoursPerDay`. This affects 22 existing entries.

Properties in Polyfill_* files were never collected

Only static polyfill files had their properties read. ProcessStartInfo.ArgumentList — a real shipping API with a //Link: — was missing from the list entirely.

Extension-block members in Polyfill_* files were sectioned by first parameter

Polyfill_BitConverter.cs uses an extension(BitConverter) block, so its methods have no this parameter. The section was derived from Parameters[0], which scattered the six statics across #### Double, #### Int32, #### Single, #### UInt32 and #### UInt64. Sectioning now comes from the enclosing extension(Type) receiver where there is one, falling back to the first parameter for classic this extension methods.

//Link: and //Note: after an attribute were ignored

An attribute list is part of the declaration, so member.GetLeadingTrivia() returns the trivia before the attribute — a comment sitting between [MethodImpl(...)] and public static is leading trivia of the public token instead, and was never seen. That silently dropped all six BitConverter references. It also meant LinkReader's ?view=net-11.0 check never ran on them, and all six URLs were indeed missing it. LinkReader now scans the modifiers as well, and the six URLs are fixed.

Ordering

BuildApiTest.RunWithRoslyn and AssemblySizeTest.MeasureAssemblySizes both read Split, but nothing ordered them after SplitterTests.Run. When they ran first they measured the previous run's Split output, which is why the committed per-framework counts were a run behind — the 15 net9 TimeSpan constants added in #591 never reached them. Both now [DependsOn] it, and this PR picks up that lag.

Result

API count 1088 → 1091 (Interlocked.And, Interlocked.Or, ProcessStartInfo.ArgumentList). Per-framework counts rise ~17 on pre-net9 targets, mostly the #591 lag. Encoding.Preamble also had a fully-qualified System.ReadOnlySpan<byte> in the source, which rendered inconsistently; shortened.

Reconciled every public member in src/Polyfill against the regenerated list — the only remaining unlisted members are those of nested helper types (ChunkEnumerator, InvocationListEnumerator, SpanSplitEnumerator, SignalHelper), which is by design.

Solution clean in Release, Consume clean across all 22 TFMs, tests green on net11.0 (1674), net10.0 (1674), net8.0 (1671), net462 (1640), plus PublicTests, EmbeddedTests, UnsafeTests, NoRefsTests and NoExtrasTests.

Five defects in the api_list generator, all of which caused shipping APIs to
be missing or mis-described:

* FeatureUnsafe was not in Identifiers.sharedIdentifiers, so InterlockedPolyfill.cs
  parsed to nothing and Interlocked.And/Or were absent, leaving an empty
  "#### Interlocked" section. Also added to the per-framework counter.
* Properties were rendered without their type, so an entry read `HoursPerDay`
  rather than `long HoursPerDay`.
* Properties in Polyfill_* files were never collected, so ProcessStartInfo.ArgumentList
  was missing entirely.
* Members of an extension(Type) block in a Polyfill_* file were sectioned by their
  first parameter, scattering the six BitConverter statics across Double, Int32,
  Single, UInt32 and UInt64.
* A //Link: or //Note: placed between a declaration's attributes and its modifiers
  was ignored, since an attribute list is part of the declaration and so is not in
  GetLeadingTrivia. That silently dropped the six BitConverter references, and with
  them the ?view=net-11.0 check that would have rejected those URLs.

BuildApiTest and AssemblySizeTest both read Split, but nothing ordered them after
SplitterTests.Run, so both could measure the previous run's output. That is why the
per-framework counts were a run behind. Both now DependsOn it.

API count 1088 -> 1091.
@SimonCropp
SimonCropp merged commit d196c56 into main Sep 10, 2026
3 of 5 checks passed
@SimonCropp
SimonCropp deleted the api-list-fixes branch September 10, 2026 03:25
SimonCropp added a commit that referenced this pull request Sep 10, 2026
Covers both the non-generic and the generic TaskCompletionSource. On frameworks
without the non-generic type the extension binds to the one Polyfill recreates,
so a single implementation serves every target.

Task does not expose the token that canceled it, so for a canceled source task
the token is recovered from the OperationCanceledException the task throws when
observed. Noted, since it costs a throw and catch the BCL avoids.

Verified against net11: an incomplete task is rejected by TrySetFromTask with an
ArgumentException rather than returning false, faulted inner exceptions are
carried over by instance and are not flattened, and a canceled task with no token
yields a token that cannot be canceled.

Also fixes two api_list defects from #592:

* Notes were emitted twice for members without an attribute list, since the
  declaration's leading trivia and its first modifier's leading trivia are the
  same trivia. Deduplicated by position, taking the note count from 107 to 61,
  which now matches the source exactly.
* A recreated type listed with WriteType emitted a second header of the same
  name when the type also had extension members, as TaskCompletionSource now
  does. WriteType merges into the existing section; WriteHelper throws rather
  than writing members under a duplicate header.

API count 1091 -> 1095.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant