diff --git a/Directory.Build.props b/Directory.Build.props
index 9ec7dd187a7..3006e8571fe 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -19,9 +19,8 @@
warning NU1507: There are 2 package sources defined in your configuration.
warning NU5104: A stable release of a package should not have a prerelease dependency. Either modify the version spec of dependency "PdfPig [0.1.9-alpha-20240510-d86c2, )" or update the version field in the nuspec.
warning NU5111: The script file 'tools\.playwright\package\bin\install_media_pack.ps1' is not recognized by NuGet and hence will not be executed during installation of this package.
- warning CS0436: IgnoresAccessChecksTo redefinition due to InternalsVisibleTo
-->
- $(NoWarn);NU1507;NU5104;NU5111;CS0436
+ $(NoWarn);NU1507;NU5104;NU5111
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 92de3602319..7b68a0f1f54 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -6,7 +6,6 @@
-
diff --git a/src/Docfx.App/Docfx.App.csproj b/src/Docfx.App/Docfx.App.csproj
index 12db285be2e..e4d0f5d7804 100644
--- a/src/Docfx.App/Docfx.App.csproj
+++ b/src/Docfx.App/Docfx.App.csproj
@@ -18,11 +18,6 @@
-
-
-
-
-
diff --git a/src/Docfx.App/Helpers/PdfPigTypeExtensions.cs b/src/Docfx.App/Helpers/PdfPigTypeExtensions.cs
new file mode 100644
index 00000000000..8b0391424c0
--- /dev/null
+++ b/src/Docfx.App/Helpers/PdfPigTypeExtensions.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Runtime.CompilerServices;
+using UglyToad.PdfPig.Content;
+using UglyToad.PdfPig.Outline.Destinations;
+
+#nullable enable
+
+namespace Docfx;
+
+internal static class PdfPigTypeExtensions
+{
+ public static NamedDestinations GetNamedDestinations(this Catalog catalog)
+ => GetNamedDestinationsProperty(catalog);
+
+ public static bool TryGet(this NamedDestinations namedDestinations, string name, out ExplicitDestination dest)
+ => TryGetNamedDestinations(namedDestinations, name, out dest);
+
+ // Gets property value of catalog.NamedDestination.
+ [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_NamedDestinations")]
+ private static extern NamedDestinations GetNamedDestinationsProperty(Catalog value);
+
+ [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "TryGet")]
+ private static extern bool TryGetNamedDestinations(NamedDestinations namedDestinations, string name, out ExplicitDestination dest);
+}
+
diff --git a/src/Docfx.App/PdfBuilder.cs b/src/Docfx.App/PdfBuilder.cs
index fdb1312dc36..0eefbe13c67 100644
--- a/src/Docfx.App/PdfBuilder.cs
+++ b/src/Docfx.App/PdfBuilder.cs
@@ -301,7 +301,7 @@ await Parallel.ForEachAsync(pages, async (item, _) =>
var key = CleanUrl(url);
if (!pagesByUrl.TryGetValue(key, out var dests))
pagesByUrl[key] = dests = new();
- dests.Add((node, document.Structure.Catalog.NamedDestinations));
+ dests.Add((node, document.Structure.Catalog.GetNamedDestinations()));
pageBytes[node] = bytes;
pageNumbers[node] = numberOfPages + 1;
diff --git a/src/Docfx.Dotnet/Docfx.Dotnet.csproj b/src/Docfx.Dotnet/Docfx.Dotnet.csproj
index 9dbc6ec171a..d28ca0fb4ae 100644
--- a/src/Docfx.Dotnet/Docfx.Dotnet.csproj
+++ b/src/Docfx.Dotnet/Docfx.Dotnet.csproj
@@ -16,10 +16,6 @@
-
-
-
-
@@ -32,7 +28,6 @@
-
diff --git a/src/Docfx.Dotnet/ExtensionMethods/ISymbolExtensions.cs b/src/Docfx.Dotnet/ExtensionMethods/ISymbolExtensions.cs
new file mode 100644
index 00000000000..362beb83f76
--- /dev/null
+++ b/src/Docfx.Dotnet/ExtensionMethods/ISymbolExtensions.cs
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.CodeAnalysis;
+using System.Collections.Immutable;
+using System.Globalization;
+using System.Reflection;
+using System.Reflection.Emit;
+
+#nullable enable
+
+namespace Docfx.Dotnet;
+
+internal static class ISymbolExtensions
+{
+ public static ImmutableArray GetParameters(this ISymbol? symbol)
+ {
+ return symbol switch
+ {
+ IMethodSymbol m => m.Parameters,
+ IPropertySymbol nt => nt.Parameters,
+ _ => [],
+ };
+ }
+
+ public static ImmutableArray GetTypeParameters(this ISymbol? symbol)
+ {
+ return symbol switch
+ {
+ IMethodSymbol m => m.TypeParameters,
+ INamedTypeSymbol nt => nt.TypeParameters,
+ _ => [],
+ };
+ }
+
+ public static DocumentationComment GetDocumentationComment(this ISymbol symbol, Compilation compilation, CultureInfo? preferredCulture = null, bool expandIncludes = false, bool expandInheritdoc = false, CancellationToken cancellationToken = default)
+ {
+ // Gets FullXmlFragment by calling `symbol.DocumentationComment(...).FullXmlFragment`
+ string fullXmlFragment = Helpers.GetFullXmlFragment(symbol, compilation, preferredCulture, expandIncludes, expandInheritdoc, cancellationToken);
+
+ return new DocumentationComment
+ {
+ FullXmlFragment = fullXmlFragment,
+ };
+ }
+
+ internal class DocumentationComment
+ {
+ public required string FullXmlFragment { get; init; }
+ }
+
+ private static class Helpers
+ {
+ ///
+ /// Gets result of `symbol.GetDocumentationComment(args).FullXmlFragment`
+ ///
+ public static string GetFullXmlFragment(ISymbol symbol, Compilation compilation, CultureInfo? preferredCulture = null, bool expandIncludes = false, bool expandInheritdoc = false, CancellationToken cancellationToken = default)
+ => CachedDelegate(symbol, compilation, preferredCulture, expandIncludes, expandInheritdoc, cancellationToken);
+
+ static Helpers()
+ {
+ CachedDelegate = GetDelegate();
+ }
+
+ private delegate string GetFullXmlFragmentDelegate(ISymbol symbol, Compilation compilation, CultureInfo? preferredCulture, bool expandIncludes, bool expandInheritdoc, CancellationToken cancellationToken);
+ private static readonly GetFullXmlFragmentDelegate CachedDelegate;
+
+ private static GetFullXmlFragmentDelegate GetDelegate()
+ {
+ // Gets Microsoft.CodeAnalysis.Workspaces assembly
+ var workspaceAssembly = typeof(Workspace).Assembly;
+
+ // Gets MethodInfo for GetDocumentationComment
+ var type = workspaceAssembly.GetType("Microsoft.CodeAnalysis.Shared.Extensions.ISymbolExtensions", throwOnError: true)!;
+ var methodInfo = type.GetMethod("GetDocumentationComment", BindingFlags.Public | BindingFlags.Static);
+
+ // Gets PropertyInfo for DocumentationComment.
+ var docCommentType = workspaceAssembly.GetType("Microsoft.CodeAnalysis.Shared.Utilities.DocumentationComment", throwOnError: true)!;
+ var propertyInfo = docCommentType.GetProperty("FullXmlFragment", BindingFlags.Instance | BindingFlags.Public)!;
+
+ // Reflection may fail when updating the Microsoft.CodeAnalysis.Workspaces.Common package..
+ if (methodInfo == null || propertyInfo == null)
+ throw new InvalidOperationException("Failed to get required MethodInfo/PropertyInfo via reflection.");
+
+ var dm = new DynamicMethod(string.Empty, returnType: typeof(string), parameterTypes: [
+ typeof(ISymbol),
+ typeof(Compilation),
+ typeof(CultureInfo), // preferredCulture
+ typeof(bool), // expandIncludes
+ typeof(bool), // expandInheritdoc
+ typeof(CancellationToken),
+ ]);
+
+ ILGenerator il = dm.GetILGenerator();
+
+ // call Microsoft.CodeAnalysis.Shared.Extensions.ISymbolExtensions::GetDocumentationComment(args)
+ il.Emit(OpCodes.Ldarg_0); // symbol
+ il.Emit(OpCodes.Ldarg_1); // compilation
+ il.Emit(OpCodes.Ldarg_2); // preferredCulture
+ il.Emit(OpCodes.Ldarg_3); // expandIncludes
+ il.Emit(OpCodes.Ldarg_S, 4); // expandInheritdoc
+ il.Emit(OpCodes.Ldarg_S, 5); // cancellationToken
+ il.EmitCall(OpCodes.Call, methodInfo, null);
+
+ // callvirt DocumentationComment::get_FullXmlFragment()
+ il.EmitCall(OpCodes.Callvirt, propertyInfo.GetMethod!, null);
+
+ // return FullXmlFragment
+ il.Emit(OpCodes.Ret);
+
+ return dm.CreateDelegate();
+ }
+ }
+}