diff --git a/src/libraries/Common/src/Roslyn/GetBestTypeByMetadataName.cs b/src/libraries/Common/src/Roslyn/GetBestTypeByMetadataName.cs
index 6a64948f3828a2..c86d7f2e00ebc4 100644
--- a/src/libraries/Common/src/Roslyn/GetBestTypeByMetadataName.cs
+++ b/src/libraries/Common/src/Roslyn/GetBestTypeByMetadataName.cs
@@ -3,9 +3,9 @@
using Microsoft.CodeAnalysis;
-namespace System.Text.Json.Reflection
+namespace Microsoft.CodeAnalysis.DotnetRuntime.Extensions
{
- internal static partial class RoslynExtensions
+ internal static class RoslynExtensions
{
// Copied from: https://github.com/dotnet/roslyn/blob/main/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/CompilationExtensions.cs
///
diff --git a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs
index fa45f5511f157e..23b1d5959aced5 100644
--- a/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs
+++ b/src/libraries/Common/tests/SourceGenerators/RoslynTestUtils.cs
@@ -48,10 +48,10 @@ public static Project CreateTestProject(IEnumerable? references, bool
}
return new AdhocWorkspace()
- .AddSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()))
- .AddProject("Test", "test.dll", "C#")
- .WithMetadataReferences(refs)
- .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Enable));
+ .AddSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Create()))
+ .AddProject("Test", "test.dll", "C#")
+ .WithMetadataReferences(refs)
+ .WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary).WithNullableContextOptions(NullableContextOptions.Enable));
}
public static Task CommitChanges(this Project proj, params string[] ignorables)
@@ -152,13 +152,24 @@ public static TextSpan MakeSpan(string text, int spanNum)
CancellationToken cancellationToken = default)
{
Project proj = CreateTestProject(references, includeBaseReferences);
-
proj = proj.WithDocuments(sources);
-
Assert.True(proj.Solution.Workspace.TryApplyChanges(proj.Solution));
-
Compilation? comp = await proj!.GetCompilationAsync(CancellationToken.None).ConfigureAwait(false);
+ return RunGenerator(comp!, generator, cancellationToken);
+ }
+ ///
+ /// Runs a Roslyn generator given a Compilation.
+ ///
+ public static (ImmutableArray, ImmutableArray) RunGenerator(
+ Compilation compilation,
+#if ROSLYN4_0_OR_GREATER
+ IIncrementalGenerator generator,
+#else
+ ISourceGenerator generator,
+#endif
+ CancellationToken cancellationToken = default)
+ {
#if ROSLYN4_0_OR_GREATER
// workaround https://github.com/dotnet/roslyn/pull/55866. We can remove "LangVersion=Preview" when we get a Roslyn build with that change.
CSharpParseOptions options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.Preview);
@@ -167,7 +178,7 @@ public static TextSpan MakeSpan(string text, int spanNum)
CSharpGeneratorDriver cgd = CSharpGeneratorDriver.Create(new[] { generator });
#endif
- GeneratorDriver gd = cgd.RunGenerators(comp!, cancellationToken);
+ GeneratorDriver gd = cgd.RunGenerators(compilation, cancellationToken);
GeneratorDriverRunResult r = gd.GetRunResult();
return (r.Results[0].Diagnostics, r.Results[0].GeneratedSources);
diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs
index 93d7590059b310..f33f506a213787 100644
--- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs
+++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/LoggerMessageGenerator.Parser.cs
@@ -10,6 +10,7 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Immutable;
+using Microsoft.CodeAnalysis.DotnetRuntime.Extensions;
namespace Microsoft.Extensions.Logging.Generators
{
@@ -65,28 +66,28 @@ internal static bool IsSyntaxTargetForGeneration(SyntaxNode node) =>
///
public IReadOnlyList GetLogClasses(IEnumerable classes)
{
- INamedTypeSymbol loggerMessageAttribute = _compilation.GetTypeByMetadataName(LoggerMessageAttribute);
+ INamedTypeSymbol loggerMessageAttribute = _compilation.GetBestTypeByMetadataName(LoggerMessageAttribute);
if (loggerMessageAttribute == null)
{
// nothing to do if this type isn't available
return Array.Empty();
}
- INamedTypeSymbol loggerSymbol = _compilation.GetTypeByMetadataName("Microsoft.Extensions.Logging.ILogger");
+ INamedTypeSymbol loggerSymbol = _compilation.GetBestTypeByMetadataName("Microsoft.Extensions.Logging.ILogger");
if (loggerSymbol == null)
{
// nothing to do if this type isn't available
return Array.Empty();
}
- INamedTypeSymbol logLevelSymbol = _compilation.GetTypeByMetadataName("Microsoft.Extensions.Logging.LogLevel");
+ INamedTypeSymbol logLevelSymbol = _compilation.GetBestTypeByMetadataName("Microsoft.Extensions.Logging.LogLevel");
if (logLevelSymbol == null)
{
// nothing to do if this type isn't available
return Array.Empty();
}
- INamedTypeSymbol exceptionSymbol = _compilation.GetTypeByMetadataName("System.Exception");
+ INamedTypeSymbol exceptionSymbol = _compilation.GetBestTypeByMetadataName("System.Exception");
if (exceptionSymbol == null)
{
Diag(DiagnosticDescriptors.MissingRequiredType, null, "System.Exception");
diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Microsoft.Extensions.Logging.Generators.targets b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Microsoft.Extensions.Logging.Generators.targets
index 2f3db63183ecdc..77a182fa4649aa 100644
--- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Microsoft.Extensions.Logging.Generators.targets
+++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/gen/Microsoft.Extensions.Logging.Generators.targets
@@ -20,4 +20,8 @@
+
+
+
+
diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/CompilationHelper.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/CompilationHelper.cs
new file mode 100644
index 00000000000000..59c82a5437147f
--- /dev/null
+++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/CompilationHelper.cs
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+
+namespace Microsoft.Extensions.Logging.Generators.Tests
+{
+ public class CompilationHelper
+ {
+ public static Compilation CreateCompilation(
+ string source,
+ MetadataReference[]? additionalReferences = null,
+ string assemblyName = "TestAssembly")
+ {
+ string corelib = Assembly.GetAssembly(typeof(object))!.Location;
+ string runtimeDir = Path.GetDirectoryName(corelib)!;
+
+ var refs = new List();
+ refs.Add(MetadataReference.CreateFromFile(corelib));
+ refs.Add(MetadataReference.CreateFromFile(Path.Combine(runtimeDir, "netstandard.dll")));
+ refs.Add(MetadataReference.CreateFromFile(Path.Combine(runtimeDir, "System.Runtime.dll")));
+ refs.Add(MetadataReference.CreateFromFile(typeof(ILogger).Assembly.Location));
+ refs.Add(MetadataReference.CreateFromFile(typeof(LoggerMessageAttribute).Assembly.Location));
+
+ if (additionalReferences != null)
+ {
+ foreach (MetadataReference reference in additionalReferences)
+ {
+ refs.Add(reference);
+ }
+ }
+
+ CSharpParseOptions options = CSharpParseOptions.Default;
+
+#if ROSLYN4_0_OR_GREATER
+ // workaround https://github.com/dotnet/roslyn/pull/55866. We can remove "LangVersion=Preview" when we get a Roslyn build with that change.
+ options = options.WithLanguageVersion(LanguageVersion.Preview);
+#endif
+
+ return CSharpCompilation.Create(
+ assemblyName,
+ syntaxTrees: new[] { CSharpSyntaxTree.ParseText(source, options) },
+ references: refs.ToArray(),
+ options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)
+ );
+ }
+
+ public static byte[] CreateAssemblyImage(Compilation compilation)
+ {
+ MemoryStream ms = new MemoryStream();
+ var emitResult = compilation.Emit(ms);
+ if (!emitResult.Success)
+ {
+ throw new InvalidOperationException();
+ }
+ return ms.ToArray();
+ }
+ }
+}
diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs
index 4ccb289f3aba7e..09b93e633335c7 100644
--- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs
+++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/tests/Microsoft.Extensions.Logging.Generators.Tests/LoggerMessageGeneratorParserTests.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Collections.Immutable;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
@@ -677,6 +678,55 @@ static partial class C
Assert.Empty(diagnostics); // should fail quietly on broken code
}
+ [Fact]
+ internal void MultipleTypeDefinitions()
+ {
+ // Adding a dependency to an assembly that has internal definitions of public types
+ // should not result in a collision and break generation.
+ // Verify usage of the extension GetBestTypeByMetadataName(this Compilation) instead of Compilation.GetTypeByMetadataName().
+ var referencedSource = @"
+ namespace Microsoft.Extensions.Logging
+ {
+ internal class LoggerMessageAttribute { }
+ }
+ namespace Microsoft.Extensions.Logging
+ {
+ internal interface ILogger { }
+ internal enum LogLevel { }
+ }";
+
+ // Compile the referenced assembly first.
+ Compilation referencedCompilation = CompilationHelper.CreateCompilation(referencedSource);
+
+ // Obtain the image of the referenced assembly.
+ byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation);
+
+ // Generate the code
+ string source = @"
+ namespace Test
+ {
+ using Microsoft.Extensions.Logging;
+
+ partial class C
+ {
+ [LoggerMessage(EventId = 1, Level = LogLevel.Debug, Message = ""M1"")]
+ static partial void M1(ILogger logger);
+ }
+ }";
+
+ MetadataReference[] additionalReferences = { MetadataReference.CreateFromImage(referencedImage) };
+ Compilation compilation = CompilationHelper.CreateCompilation(source, additionalReferences);
+ LoggerMessageGenerator generator = new LoggerMessageGenerator();
+
+ (ImmutableArray diagnostics, ImmutableArray generatedSources) =
+ RoslynTestUtils.RunGenerator(compilation, generator);
+
+ // Make sure compilation was successful.
+ Assert.Empty(diagnostics);
+ Assert.Equal(1, generatedSources.Length);
+ Assert.Equal(21, generatedSources[0].SourceText.Lines.Count);
+ }
+
private static async Task> RunGenerator(
string code,
bool wrap = true,
diff --git a/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Parser.cs b/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Parser.cs
index be971bb185f0b8..2b28b46e03335b 100644
--- a/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Parser.cs
+++ b/src/libraries/System.Private.CoreLib/generators/EventSourceGenerator.Parser.cs
@@ -7,10 +7,10 @@
using System.Security.Cryptography;
using System.Text;
using System.Threading;
-
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.DotnetRuntime.Extensions;
namespace Generators
{
@@ -31,14 +31,14 @@ public Parser(Compilation compilation, Action reportDiagnostic, Canc
public EventSourceClass[] GetEventSourceClasses(List classDeclarations)
{
- INamedTypeSymbol? autogenerateAttribute = _compilation.GetTypeByMetadataName("System.Diagnostics.Tracing.EventSourceAutoGenerateAttribute");
+ INamedTypeSymbol? autogenerateAttribute = _compilation.GetBestTypeByMetadataName("System.Diagnostics.Tracing.EventSourceAutoGenerateAttribute");
if (autogenerateAttribute is null)
{
// No EventSourceAutoGenerateAttribute
return Array.Empty();
}
- INamedTypeSymbol? eventSourceAttribute = _compilation.GetTypeByMetadataName("System.Diagnostics.Tracing.EventSourceAttribute");
+ INamedTypeSymbol? eventSourceAttribute = _compilation.GetBestTypeByMetadataName("System.Diagnostics.Tracing.EventSourceAttribute");
if (eventSourceAttribute is null)
{
// No EventSourceAttribute
diff --git a/src/libraries/System.Private.CoreLib/generators/System.Private.CoreLib.Generators.csproj b/src/libraries/System.Private.CoreLib/generators/System.Private.CoreLib.Generators.csproj
index bf6c663b56432f..451bb520f66ead 100644
--- a/src/libraries/System.Private.CoreLib/generators/System.Private.CoreLib.Generators.csproj
+++ b/src/libraries/System.Private.CoreLib/generators/System.Private.CoreLib.Generators.csproj
@@ -15,6 +15,7 @@
+
diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
index e5cb105b39d6e4..e985f1c3c38a7e 100644
--- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
+++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs
@@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.DotnetRuntime.Extensions;
using Microsoft.CodeAnalysis.Text;
namespace System.Text.Json.SourceGeneration
diff --git a/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs b/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs
index 189a842f44f5c6..15020ec6ea6217 100644
--- a/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs
+++ b/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs
@@ -7,6 +7,7 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.DotnetRuntime.Extensions;
namespace System.Text.Json.Reflection
{
diff --git a/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs b/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs
index aa3f431fced8d0..62afc237624a15 100644
--- a/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs
+++ b/src/libraries/System.Text.Json/gen/Reflection/RoslynExtensions.cs
@@ -7,7 +7,7 @@
namespace System.Text.Json.Reflection
{
- internal static partial class RoslynExtensions
+ internal static class RoslynExtensions
{
public static Type AsType(this ITypeSymbol typeSymbol, MetadataLoadContextInternal metadataLoadContext)
{
diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs
index 0aa811d64fcce4..105dc91af17b38 100644
--- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs
+++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Unit.Tests/JsonSourceGeneratorTests.cs
@@ -474,7 +474,7 @@ public void TestMultipleDefinitions()
{
// Adding a dependency to an assembly that has internal definitions of public types
// should not result in a collision and break generation.
- // This verifies the usage of GetBestTypeByMetadataName() instead of GetTypeByMetadataName().
+ // Verify usage of the extension GetBestTypeByMetadataName(this Compilation) instead of Compilation.GetTypeByMetadataName().
var referencedSource = @"
namespace System.Text.Json.Serialization
{
@@ -487,16 +487,7 @@ internal class JsonSourceGenerationOptionsAttribute { }
Compilation referencedCompilation = CompilationHelper.CreateCompilation(referencedSource);
// Obtain the image of the referenced assembly.
- byte[] referencedImage;
- using (MemoryStream ms = new MemoryStream())
- {
- var emitResult = referencedCompilation.Emit(ms);
- if (!emitResult.Success)
- {
- throw new InvalidOperationException();
- }
- referencedImage = ms.ToArray();
- }
+ byte[] referencedImage = CompilationHelper.CreateAssemblyImage(referencedCompilation);
// Generate the code
string source = @"
diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj
index 69f0e7bbed025c..af4c31639bb4e3 100644
--- a/src/libraries/tests.proj
+++ b/src/libraries/tests.proj
@@ -15,8 +15,14 @@
-
-
+
+
+
+
+
+
+
+