KirillOsenkov / SourceBrowser

Source browser website generator that powers http://referencesource.microsoft.com and http://sourceroslyn.io
Apache License 2.0
1.08k stars 197 forks source link

Update Roslyn to v4.4.0 #224

Closed ltrzesniewski closed 1 year ago

ltrzesniewski commented 1 year ago

This PR updates Roslyn to v4.4.0.

I was getting the following error with the .NET 7 SDK:

Unhandled Exception: System.MissingMethodException: Method not found: 'Void Microsoft.NET.StringTools.SpanBasedStringBuilder.Append(System.ReadOnlyMemory`1<Char>)'.
  at Microsoft.Build.Evaluation.Expander`2.SpanBasedConcatenator.Add(ReadOnlyMemory`1 span)
  at Microsoft.Build.Evaluation.Expander`2.PropertyExpander`1.ExpandPropertiesLeaveTypedAndEscaped(String expression, IPropertyProvider`1 properties, ExpanderOptions options, IElementLocation elementLocation, UsedUninitializedProperties usedUninitializedProperties, IFileSystem fileSystem, LoggingContext loggingContext)
  at Microsoft.Build.Evaluation.Expander`2.PropertyExpander`1.ExpandPropertiesLeaveEscaped(String expression, IPropertyProvider`1 properties, ExpanderOptions options, IElementLocation elementLocation, UsedUninitializedProperties usedUninitializedProperties, IFileSystem fileSystem, LoggingContext loggingContext)
  at Microsoft.Build.Evaluation.Expander`2.ExpandIntoStringLeaveEscaped(String expression, ExpanderOptions options, IElementLocation elementLocation, LoggingContext loggingContext)
  at Microsoft.Build.Evaluation.ToolsetReader.ExpandPropertyUnescaped(ToolsetPropertyDefinition property, Expander`2 expander)
  at Microsoft.Build.Evaluation.ToolsetReader.EvaluateAndSetProperty(ToolsetPropertyDefinition property, PropertyDictionary`1 properties, PropertyDictionary`1 globalProperties, PropertyDictionary`1 initialProperties, Boolean accumulateProperties, String& toolsPath, String& binPath, Expander`2& expander)
  at Microsoft.Build.Evaluation.ToolsetReader.ReadToolset(ToolsetPropertyDefinition toolsVersion, PropertyDictionary`1 globalProperties, PropertyDictionary`1 initialProperties, Boolean accumulateProperties)
  at Microsoft.Build.Evaluation.ToolsetReader.ReadEachToolset(Dictionary`2 toolsets, PropertyDictionary`1 globalProperties, PropertyDictionary`1 initialProperties, Boolean accumulateProperties)
  at Microsoft.Build.Evaluation.ToolsetReader.ReadToolsets(Dictionary`2 toolsets, PropertyDictionary`1 globalProperties, PropertyDictionary`1 initialProperties, Boolean accumulateProperties, String& msBuildOverrideTasksPath, String& defaultOverrideToolsVersion)
  at Microsoft.Build.Evaluation.ToolsetReader.<ReadAllToolsets>g__ReadConfigToolset|12_0(<>c__DisplayClass12_0& )
  at Microsoft.Build.Evaluation.ToolsetReader.ReadAllToolsets(Dictionary`2 toolsets, ToolsetRegistryReader registryReader, ToolsetConfigurationReader configurationReader, PropertyDictionary`1 environmentProperties, PropertyDictionary`1 globalProperties, ToolsetDefinitionLocations locations)
  at Microsoft.Build.Evaluation.ProjectCollection.InitializeToolsetCollection(ToolsetRegistryReader registryReader, ToolsetConfigurationReader configReader)
  at Microsoft.Build.Evaluation.ProjectCollection..ctor(IDictionary`2 globalProperties, IEnumerable`1 loggers, IEnumerable`1 remoteLoggers, ToolsetDefinitionLocations toolsetDefinitionLocations, Int32 maxNodeCount, Boolean onlyLogCriticalEvents, Boolean loadProjectsReadOnly, Boolean useAsynchronousLogging, Boolean reuseProjectRootElementCache)
  at Microsoft.Build.Evaluation.ProjectCollection.get_GlobalProjectCollection()
  at Microsoft.SourceBrowser.Common.AssemblyNameExtractor.GetAssemblyNameFromProject(String projectFilePath)
  at Microsoft.SourceBrowser.Common.AssemblyNameExtractor.GetAssemblyNames(String projectOrSolutionFilePath)
  at Microsoft.SourceBrowser.HtmlGenerator.Program.IndexSolutions(IEnumerable`1 solutionFilePaths, IReadOnlyDictionary`2 properties, Federation federation, IReadOnlyDictionary`2 serverPathMappings, IEnumerable`1 pluginBlacklist, Boolean doNotIncludeReferencedProjects, String rootPath) in C:\SourceBrowser\src\HtmlGenerator\Program.cs:line 125
  at Microsoft.SourceBrowser.HtmlGenerator.Program.Main(String[] args) in C:\SourceBrowser\src\HtmlGenerator\Program.cs:line 20

It seems to work at first glance after the update, though maybe I didn't check thoroughly enough.

I kept MSBuild at the current version, as I wasn't sure if you'd rather keep it that way. I just added a NuGetVersionMSBuild property for consistency. Also, the MEF assembly references an older version of Roslyn, and I wasn't sure if I should update it, so I left it as-is.

ltrzesniewski commented 1 year ago

I also noticed that this signature is outdated:

https://github.com/KirillOsenkov/SourceBrowser/blob/2b57a3d551d02c05b90d006f48cfa07c0a7e5cd2/src/HtmlGenerator/Pass1-Generation/MetadataAsSource.cs#L24-L25

It's the case for a long time though: https://github.com/dotnet/roslyn/pull/33183 introduced the first change (in 2019).

KirillOsenkov commented 1 year ago

Thanks so much! This is big help.

KirillOsenkov commented 1 year ago

Oh, and regarding the signature of IMetadataAsSourceService.AddSourceToAsync, you're absolutely right, they've changed it in a way that makes it impossible to create a delegate for (because of the internal type https://sourceroslyn.io/#Microsoft.CodeAnalysis.Workspaces/CleanCodeGenerationOptions.cs,6b9a1e6e70bb2183).

Ideally we'd need to rewrite this entire piece to just decompile using ILSpy and not rely on Roslyn's internal API. However it's a non-trivial amount of work and I don't know if there are a lot of users that index .dll files for Metadata-as-source, so unfortunately I'll have to table it for now.

ltrzesniewski commented 1 year ago

Well, I suppose you could create the internal type using Activator.CreateInstance then call the method through reflection (or IL emitted code if it needs to be fast), but that won't be pretty...

Another option would be to use IgnoresAccessChecksToGenerator to gain access to all of Roslyn's internal APIs through IgnoresAccessChecksToAttribute. That's what RoslynPad does for instance.

It's a bit of a shame that Roslyn doesn't make more of its APIs public. This hides some of the value the platform can bring, and forces projects that want to leverage it to jump through hoops, just like the name of your WorkspaceHacks class shows. I also needed to use hacks for an internal tool with a C# expression editor for instance. 😞

Thanks for the release BTW 🙂

KirillOsenkov commented 1 year ago

Tell me about it! Roslyn causes me so much pain too, not just in this project!

ltrzesniewski commented 1 year ago

Damn 😬

Hopefully someday the Roslyn team will consider making more of their features public. Even having some APIs which would be marked as "unstable", in the sense that they would be allowed to change between minor releases, could be helpful.