From ae90dbb9c70b9969a0074a42be1c9e6993dd238d Mon Sep 17 00:00:00 2001 From: Jared Parsons Date: Wed, 16 Oct 2024 22:34:48 -0700 Subject: [PATCH] fix AppDomain pollution --- .../AppDomainUtils.cs | 98 ++++++++++++ .../BinaryLogReaderTests.cs | 15 +- .../CodeAnalysisExtensionTests.cs | 2 +- .../CompilationDataTests.cs | 150 ++++++++++-------- .../CompilerLogReaderTests.cs | 20 +-- .../SolutionReaderTests.cs | 3 +- src/Basic.CompilerLog.UnitTests/TestBase.cs | 92 +++++++++++ .../UsingAllCompilerLogTests.cs | 4 +- src/Basic.CompilerLog.Util/CompilationData.cs | 14 +- .../Impl/BasicAnalyzerHostOnDisk.cs | 2 +- 10 files changed, 304 insertions(+), 96 deletions(-) create mode 100644 src/Basic.CompilerLog.UnitTests/AppDomainUtils.cs diff --git a/src/Basic.CompilerLog.UnitTests/AppDomainUtils.cs b/src/Basic.CompilerLog.UnitTests/AppDomainUtils.cs new file mode 100644 index 0000000..b2ccc0a --- /dev/null +++ b/src/Basic.CompilerLog.UnitTests/AppDomainUtils.cs @@ -0,0 +1,98 @@ +#if NETFRAMEWORK +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Xunit.Abstractions; + +namespace Basic.CompilerLog.UnitTests; + +public static class AppDomainUtils +{ + private static readonly object s_lock = new object(); + private static bool s_hookedResolve; + + public static AppDomain Create(string? name = null, string? basePath = null) + { + name = name ?? "Custom AppDomain"; + basePath = basePath ?? Path.GetDirectoryName(typeof(AppDomainUtils).Assembly.Location); + + lock (s_lock) + { + if (!s_hookedResolve) + { + AppDomain.CurrentDomain.AssemblyResolve += OnResolve; + s_hookedResolve = true; + } + } + + return AppDomain.CreateDomain(name, null, new AppDomainSetup() + { + ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile, + ApplicationBase = basePath + }); + } + + /// + /// When run under xunit without AppDomains all DLLs get loaded via the AssemblyResolve + /// event. In some cases the xunit, AppDomain marshalling, xunit doesn't fully hook + /// the event and we need to do it for our assemblies. + /// + private static Assembly? OnResolve(object sender, ResolveEventArgs e) + { + var assemblyName = new AssemblyName(e.Name); + var fullPath = Path.Combine( + Path.GetDirectoryName(typeof(AppDomainUtils).Assembly.Location), + assemblyName.Name + ".dll"); + if (File.Exists(fullPath)) + { + return Assembly.LoadFrom(fullPath); + } + + return null; + } +} + +public sealed class AppDomainTestOutputHelper : MarshalByRefObject, ITestOutputHelper +{ + public ITestOutputHelper TestOutputHelper { get; } + + public AppDomainTestOutputHelper(ITestOutputHelper testOutputHelper) + { + TestOutputHelper = testOutputHelper; + } + + public void WriteLine(string message) => + TestOutputHelper.WriteLine(message); + + public void WriteLine(string format, params object[] args) => + TestOutputHelper.WriteLine(format, args); +} + +public sealed class InvokeUtil : MarshalByRefObject +{ + internal void Invoke(string typeName, string methodName, ITestOutputHelper testOutputHelper, T state) + { + var type = typeof(AppDomainUtils).Assembly.GetType(typeName, throwOnError: false)!; + var member = type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)!; + + // A static lambda will still be an instance method so we need to create the closure + // here. + var obj = member.IsStatic + ? null + : type.Assembly.CreateInstance(typeName); + + try + { + member.Invoke(obj, [testOutputHelper, state]); + } + catch (TargetInvocationException ex) + { + throw new Exception(ex.InnerException.Message); + } + } +} + +#endif diff --git a/src/Basic.CompilerLog.UnitTests/BinaryLogReaderTests.cs b/src/Basic.CompilerLog.UnitTests/BinaryLogReaderTests.cs index 87baf50..4557eaa 100644 --- a/src/Basic.CompilerLog.UnitTests/BinaryLogReaderTests.cs +++ b/src/Basic.CompilerLog.UnitTests/BinaryLogReaderTests.cs @@ -137,12 +137,15 @@ public void VerifyBasicAnalyzerKind(BasicAnalyzerKind basicAnalyzerKind) [MemberData(nameof(GetSupportedBasicAnalyzerKinds))] public void GetCompilationSimple(BasicAnalyzerKind basicAnalyzerKind) { - using var reader = BinaryLogReader.Create(Fixture.Console.Value.BinaryLogPath!, basicAnalyzerKind); - var compilerCall = reader.ReadAllCompilerCalls().First(); - var compilationData = reader.ReadCompilationData(compilerCall); - Assert.NotNull(compilationData); - var emitResult = compilationData.EmitToMemory(); - Assert.True(emitResult.Success); + RunInContext((FilePath: Fixture.Console.Value.BinaryLogPath!, Kind: basicAnalyzerKind), static (testOutptuHelper, state) => + { + using var reader = BinaryLogReader.Create(state.FilePath, state.Kind); + var compilerCall = reader.ReadAllCompilerCalls().First(); + var compilationData = reader.ReadCompilationData(compilerCall); + Assert.NotNull(compilationData); + var emitResult = compilationData.EmitToMemory(); + Assert.True(emitResult.Success); + }); } [Fact] diff --git a/src/Basic.CompilerLog.UnitTests/CodeAnalysisExtensionTests.cs b/src/Basic.CompilerLog.UnitTests/CodeAnalysisExtensionTests.cs index 6f40e51..e00dbff 100644 --- a/src/Basic.CompilerLog.UnitTests/CodeAnalysisExtensionTests.cs +++ b/src/Basic.CompilerLog.UnitTests/CodeAnalysisExtensionTests.cs @@ -20,7 +20,7 @@ public CodeAnalysisExtensionsTests(ITestOutputHelper testOutputHelper, CompilerL [Fact] public void EmitToMemory() { - var data = GetCompilationData(Fixture.ClassLib.Value.CompilerLogPath); + var data = GetCompilationData(Fixture.ClassLib.Value.CompilerLogPath, basicAnalyzerKind: BasicAnalyzerKind.None); var compilation = data.GetCompilationAfterGenerators(); var result = compilation.EmitToMemory(EmitFlags.Default); AssertEx.Success(TestOutputHelper, result); diff --git a/src/Basic.CompilerLog.UnitTests/CompilationDataTests.cs b/src/Basic.CompilerLog.UnitTests/CompilationDataTests.cs index 6b05582..0d070bb 100644 --- a/src/Basic.CompilerLog.UnitTests/CompilationDataTests.cs +++ b/src/Basic.CompilerLog.UnitTests/CompilationDataTests.cs @@ -20,60 +20,69 @@ public CompilationDataTests(ITestOutputHelper testOutputHelper, CompilerLogFixtu [Fact] public void EmitToMemoryCombinations() { - using var reader = CompilerLogReader.Create(Fixture.ClassLib.Value.CompilerLogPath); - var data = reader.ReadCompilationData(0); - - var emitResult = data.EmitToMemory(); - Assert.True(emitResult.Success); - AssertEx.HasData(emitResult.AssemblyStream); - AssertEx.HasData(emitResult.PdbStream); - Assert.Null(emitResult.XmlStream); - AssertEx.HasData(emitResult.MetadataStream); - - emitResult = data.EmitToMemory(EmitFlags.IncludePdbStream); - Assert.True(emitResult.Success); - AssertEx.HasData(emitResult.AssemblyStream); - AssertEx.HasData(emitResult.PdbStream); - Assert.Null(emitResult.XmlStream); - Assert.Null(emitResult.MetadataStream); - - emitResult = data.EmitToMemory(EmitFlags.IncludePdbStream | EmitFlags.IncludeXmlStream); - Assert.True(emitResult.Success); - AssertEx.HasData(emitResult.AssemblyStream); - AssertEx.HasData(emitResult.PdbStream); - AssertEx.HasData(emitResult.XmlStream); - Assert.Null(emitResult.MetadataStream); - - emitResult = data.EmitToMemory(EmitFlags.IncludePdbStream | EmitFlags.IncludeXmlStream | EmitFlags.IncludeMetadataStream); - Assert.True(emitResult.Success); - AssertEx.HasData(emitResult.AssemblyStream); - AssertEx.HasData(emitResult.PdbStream); - AssertEx.HasData(emitResult.XmlStream); - AssertEx.HasData(emitResult.MetadataStream); - - emitResult = data.EmitToMemory(EmitFlags.MetadataOnly); - Assert.True(emitResult.Success); - AssertEx.HasData(emitResult.AssemblyStream); - Assert.Null(emitResult.PdbStream); - Assert.Null(emitResult.XmlStream); - Assert.Null(emitResult.MetadataStream); + RunInContext(Fixture.ClassLib.Value.CompilerLogPath, static (testOutputHelper, filePath) => + { + using var reader = CompilerLogReader.Create(filePath); + var data = reader.ReadCompilationData(0); + + var emitResult = data.EmitToMemory(); + Assert.True(emitResult.Success); + AssertEx.HasData(emitResult.AssemblyStream); + AssertEx.HasData(emitResult.PdbStream); + Assert.Null(emitResult.XmlStream); + AssertEx.HasData(emitResult.MetadataStream); + + emitResult = data.EmitToMemory(EmitFlags.IncludePdbStream); + Assert.True(emitResult.Success); + AssertEx.HasData(emitResult.AssemblyStream); + AssertEx.HasData(emitResult.PdbStream); + Assert.Null(emitResult.XmlStream); + Assert.Null(emitResult.MetadataStream); + + emitResult = data.EmitToMemory(EmitFlags.IncludePdbStream | EmitFlags.IncludeXmlStream); + Assert.True(emitResult.Success); + AssertEx.HasData(emitResult.AssemblyStream); + AssertEx.HasData(emitResult.PdbStream); + AssertEx.HasData(emitResult.XmlStream); + Assert.Null(emitResult.MetadataStream); + + emitResult = data.EmitToMemory(EmitFlags.IncludePdbStream | EmitFlags.IncludeXmlStream | EmitFlags.IncludeMetadataStream); + Assert.True(emitResult.Success); + AssertEx.HasData(emitResult.AssemblyStream); + AssertEx.HasData(emitResult.PdbStream); + AssertEx.HasData(emitResult.XmlStream); + AssertEx.HasData(emitResult.MetadataStream); + + emitResult = data.EmitToMemory(EmitFlags.MetadataOnly); + Assert.True(emitResult.Success); + AssertEx.HasData(emitResult.AssemblyStream); + Assert.Null(emitResult.PdbStream); + Assert.Null(emitResult.XmlStream); + Assert.Null(emitResult.MetadataStream); + }); } [Fact] public void EmitToMemoryRefOnly() { - using var reader = CompilerLogReader.Create(Fixture.ClassLibRefOnly.Value.CompilerLogPath); - var data = reader.ReadCompilationData(0); - var result = data.EmitToMemory(); - Assert.True(result.Success); + RunInContext(Fixture.ClassLibRefOnly.Value.CompilerLogPath, static (testOutputHelper, filePath) => + { + using var reader = CompilerLogReader.Create(filePath); + var data = reader.ReadCompilationData(0); + var result = data.EmitToMemory(); + Assert.True(result.Success); + }); } [Fact] public void GetAnalyzersNormal() { - using var reader = CompilerLogReader.Create(Fixture.ClassLib.Value.CompilerLogPath); - var data = reader.ReadCompilationData(0); - Assert.NotEmpty(data.GetAnalyzers()); + RunInContext(Fixture.ClassLib.Value.CompilerLogPath, static (testOtputHelper, filePath) => + { + using var reader = CompilerLogReader.Create(filePath); + var data = reader.ReadCompilationData(0); + Assert.NotEmpty(data.GetAnalyzers()); + }); } [Fact] @@ -87,7 +96,7 @@ public void GetAnalyzersNoHosting() [Fact] public void GetDiagnostics() { - using var reader = CompilerLogReader.Create(Fixture.ClassLib.Value.CompilerLogPath, BasicAnalyzerHost.DefaultKind); + using var reader = CompilerLogReader.Create(Fixture.ClassLib.Value.CompilerLogPath, BasicAnalyzerKind.None); var data = reader.ReadCompilationData(0); Assert.NotEmpty(data.GetDiagnostics()); } @@ -95,7 +104,7 @@ public void GetDiagnostics() [Fact] public async Task GetAllDiagnostics() { - using var reader = CompilerLogReader.Create(Fixture.ClassLib.Value.CompilerLogPath, BasicAnalyzerHost.DefaultKind); + using var reader = CompilerLogReader.Create(Fixture.ClassLib.Value.CompilerLogPath, BasicAnalyzerKind.None); var data = reader.ReadCompilationData(0); Assert.NotEmpty(await data.GetAllDiagnosticsAsync()); } @@ -103,32 +112,35 @@ public async Task GetAllDiagnostics() [Fact] public void GetCompilationAfterGeneratorsDiagnostics() { - using var reader = CompilerLogReader.Create( - Fixture.Console.Value.CompilerLogPath, - BasicAnalyzerHost.DefaultKind); - var rawData = reader.ReadRawCompilationData(0).Item2; - var analyzers = rawData.Analyzers - .Where(x => x.FileName != "Microsoft.CodeAnalysis.NetAnalyzers.dll") - .ToList(); - BasicAnalyzerHost host = DotnetUtil.IsNetCore - ? new BasicAnalyzerHostInMemory(reader, analyzers) - : new BasicAnalyzerHostOnDisk(reader, analyzers); - var data = (CSharpCompilationData)reader.ReadCompilationData(0); - data = new CSharpCompilationData( - data.CompilerCall, - data.Compilation, - data.ParseOptions, - data.EmitOptions, - data.EmitData, - data.AdditionalTexts, - host, - data.AnalyzerConfigOptionsProvider); - _ = data.GetCompilationAfterGenerators(out var diagnostics); - Assert.NotEmpty(diagnostics); + RunInContext(Fixture.Console.Value.CompilerLogPath, static (testOutputHelper, logFilePath) => + { + using var reader = CompilerLogReader.Create( + logFilePath, + BasicAnalyzerHost.DefaultKind); + var rawData = reader.ReadRawCompilationData(0).Item2; + var analyzers = rawData.Analyzers + .Where(x => x.FileName != "Microsoft.CodeAnalysis.NetAnalyzers.dll") + .ToList(); + BasicAnalyzerHost host = DotnetUtil.IsNetCore + ? new BasicAnalyzerHostInMemory(reader, analyzers) + : new BasicAnalyzerHostOnDisk(reader, analyzers); + var data = (CSharpCompilationData)reader.ReadCompilationData(0); + data = new CSharpCompilationData( + data.CompilerCall, + data.Compilation, + data.ParseOptions, + data.EmitOptions, + data.EmitData, + data.AdditionalTexts, + host, + data.AnalyzerConfigOptionsProvider); + _ = data.GetCompilationAfterGenerators(out var diagnostics); + Assert.NotEmpty(diagnostics); + }); } [Theory] - [MemberData(nameof(GetSupportedBasicAnalyzerKinds))] + [MemberData(nameof(GetSimpleBasicAnalyzerKinds))] public void GetGeneratedSyntaxTrees(BasicAnalyzerKind basicAnalyzerKind) { using var reader = CompilerLogReader.Create(Fixture.Console.Value.CompilerLogPath, basicAnalyzerKind); diff --git a/src/Basic.CompilerLog.UnitTests/CompilerLogReaderTests.cs b/src/Basic.CompilerLog.UnitTests/CompilerLogReaderTests.cs index 929eab4..d8306d8 100644 --- a/src/Basic.CompilerLog.UnitTests/CompilerLogReaderTests.cs +++ b/src/Basic.CompilerLog.UnitTests/CompilerLogReaderTests.cs @@ -179,19 +179,13 @@ public void AdditionalFiles() Assert.NotNull(options); } - [Fact] - public void AnalyzerLoadOptions() + [Theory] + [MemberData(nameof(GetSupportedBasicAnalyzerKinds))] + public void AnalyzerLoadOptions(BasicAnalyzerKind basicAnalyzerKind) { - var any = false; - foreach (BasicAnalyzerKind kind in Enum.GetValues(typeof(BasicAnalyzerKind))) + RunInContext((FilePath: Fixture.Console.Value.CompilerLogPath, Kind: basicAnalyzerKind), static (testOutputHelper, state) => { - if (!BasicAnalyzerHost.IsSupported(kind)) - { - continue; - } - any = true; - - using var reader = CompilerLogReader.Create(Fixture.Console.Value.CompilerLogPath, kind); + using var reader = CompilerLogReader.Create(state.FilePath, state.Kind); var data = reader.ReadCompilationData(0); var compilation = data.GetCompilationAfterGenerators(out var diagnostics); Assert.Empty(diagnostics); @@ -206,9 +200,7 @@ public void AnalyzerLoadOptions() } Assert.True(found); data.BasicAnalyzerHost.Dispose(); - } - - Assert.True(any); + }); } [Theory] diff --git a/src/Basic.CompilerLog.UnitTests/SolutionReaderTests.cs b/src/Basic.CompilerLog.UnitTests/SolutionReaderTests.cs index b72c104..a182504 100644 --- a/src/Basic.CompilerLog.UnitTests/SolutionReaderTests.cs +++ b/src/Basic.CompilerLog.UnitTests/SolutionReaderTests.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; using Xunit; @@ -42,7 +43,7 @@ private Solution GetSolution(string compilerLogFilePath, BasicAnalyzerKind basic } [Theory] - [MemberData(nameof(GetSupportedBasicAnalyzerKinds))] + [MemberData(nameof(GetSimpleBasicAnalyzerKinds))] public async Task DocumentsGeneratedDefaultHost(BasicAnalyzerKind basicAnalyzerKind) { var solution = GetSolution(Fixture.Console.Value.CompilerLogPath, basicAnalyzerKind); diff --git a/src/Basic.CompilerLog.UnitTests/TestBase.cs b/src/Basic.CompilerLog.UnitTests/TestBase.cs index f5548fe..35e4083 100644 --- a/src/Basic.CompilerLog.UnitTests/TestBase.cs +++ b/src/Basic.CompilerLog.UnitTests/TestBase.cs @@ -1,13 +1,17 @@ using Basic.CompilerLog.Util; +using Basic.CompilerLog.Util.Impl; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Drawing; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; +using Xunit.Sdk; namespace Basic.CompilerLog.UnitTests; @@ -16,11 +20,17 @@ public abstract class TestBase : IDisposable private static readonly object Guard = new(); internal static readonly Encoding DefaultEncoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); + + private List BadAssemblyLoadList { get; } = new(); internal ITestOutputHelper TestOutputHelper { get; } internal TempDir Root { get; } internal Util.LogReaderState State { get; } internal string RootDirectory => Root.DirectoryPath; + /// + /// Get all of the supported + /// + /// public static IEnumerable GetSupportedBasicAnalyzerKinds() { yield return new object[] { BasicAnalyzerKind.None }; @@ -32,15 +42,42 @@ public static IEnumerable GetSupportedBasicAnalyzerKinds() } } + /// + /// Return the that do not pollute address space and + /// can be run simply. + /// + /// + public static IEnumerable GetSimpleBasicAnalyzerKinds() + { + yield return new object[] { BasicAnalyzerKind.None }; + + if (DotnetUtil.IsNetCore) + { + yield return new object[] { BasicAnalyzerKind.OnDisk }; + yield return new object[] { BasicAnalyzerKind.InMemory }; + } + } + protected TestBase(ITestOutputHelper testOutputHelper, string name) { TestOutputHelper = testOutputHelper; Root = new TempDir(name); State = new Util.LogReaderState(Root.NewDirectory("state")); + AppDomain.CurrentDomain.AssemblyLoad += OnAssemblyLoad; } public virtual void Dispose() { + AppDomain.CurrentDomain.AssemblyLoad -= OnAssemblyLoad; + if (BadAssemblyLoadList.Count > 0) + { + TestOutputHelper.WriteLine("Bad assembly loads"); + foreach (var assemblyFilePath in BadAssemblyLoadList) + { + TestOutputHelper.WriteLine($"\t{assemblyFilePath}"); + } + Assert.Fail("Bad assembly loads"); + } TestOutputHelper.WriteLine("Deleting temp directory"); Root.Dispose(); } @@ -125,4 +162,59 @@ internal static ProcessResult RunBuildCmd(string directory) => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ProcessUtil.Run("cmd", args: "/c build.cmd", workingDirectory: directory) : ProcessUtil.Run(Path.Combine(directory, "build.sh"), args: "", workingDirectory: directory); + + protected void RunInContext(T state, Action action, [CallerMemberName] string? testMethod = null) + { +#if NETFRAMEWORK + AppDomain? appDomain = null; + try + { + appDomain = AppDomainUtils.Create($"Test {testMethod}"); + var testOutputHelper = new AppDomainTestOutputHelper(TestOutputHelper); + var type = typeof(InvokeUtil); + var util = (InvokeUtil)appDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName); + util.Invoke(action.Method.DeclaringType.FullName, action.Method.Name, testOutputHelper, state); + } + finally + { + AppDomain.Unload(appDomain); + } +#else + // On .NET Core the analyzers naturally load into child load contexts so no need for complicated + // marshalling here. + action(TestOutputHelper, state); +#endif + + } + + /// + /// This tracks assembly loads to make sure that we aren't polluting the main + /// When we load analyzers from tests into the main that potentially pollutes + /// or interferes with other tests. Instead each test should be loading into their own. + /// + private void OnAssemblyLoad(object? sender, AssemblyLoadEventArgs e) + { + var assembly = e.LoadedAssembly; + if (assembly.IsDynamic) + { + return; + } + +#if NETFRAMEWORK + if (assembly.GlobalAssemblyCache) + { + return; + } +#endif + + var name = assembly.FullName; + var location = e.LoadedAssembly.Location; + var assemblyDir = Path.GetDirectoryName(location); + var testDir = Path.GetDirectoryName(typeof(TestBase).Assembly.Location); + if (!string.Equals(assemblyDir, testDir, PathUtil.Comparison)) + { + BadAssemblyLoadList.Add(Path.GetFileName(location)); + } + } + } diff --git a/src/Basic.CompilerLog.UnitTests/UsingAllCompilerLogTests.cs b/src/Basic.CompilerLog.UnitTests/UsingAllCompilerLogTests.cs index e148752..1d523c9 100644 --- a/src/Basic.CompilerLog.UnitTests/UsingAllCompilerLogTests.cs +++ b/src/Basic.CompilerLog.UnitTests/UsingAllCompilerLogTests.cs @@ -29,7 +29,7 @@ public async Task EmitToDisk() { var task = Task.Run(() => { - using var reader = CompilerLogReader.Create(complogPath); + using var reader = CompilerLogReader.Create(complogPath, basicAnalyzerKind: BasicAnalyzerKind.None); foreach (var data in reader.ReadAllCompilationData()) { using var testDir = new TempDir(); @@ -95,7 +95,7 @@ public async Task GeneratedFilePathsNoneHost() } [Theory] - [MemberData(nameof(GetSupportedBasicAnalyzerKinds))] + [MemberData(nameof(GetSimpleBasicAnalyzerKinds))] public async Task EmitToMemory(BasicAnalyzerKind basicAnalyzerKind) { TestOutputHelper.WriteLine($"BasicAnalyzerKind: {basicAnalyzerKind}"); diff --git a/src/Basic.CompilerLog.Util/CompilationData.cs b/src/Basic.CompilerLog.Util/CompilationData.cs index f89b943..eb58758 100644 --- a/src/Basic.CompilerLog.Util/CompilationData.cs +++ b/src/Basic.CompilerLog.Util/CompilationData.cs @@ -198,8 +198,18 @@ public ImmutableArray GetDiagnostics(CancellationToken cancellationT public async Task> GetAllDiagnosticsAsync(CancellationToken cancellationToken = default) { var compilation = GetCompilationAfterGenerators(out var hostDiagnostics, cancellationToken); - var cwa = new CompilationWithAnalyzers(compilation, GetAnalyzers(), AnalyzerOptions); - var diagnostics = await cwa.GetAllDiagnosticsAsync().ConfigureAwait(false); + var analyzers = GetAnalyzers(); + ImmutableArray diagnostics; + if (analyzers.IsDefaultOrEmpty) + { + diagnostics = compilation.GetDiagnostics(cancellationToken); + } + else + { + var cwa = new CompilationWithAnalyzers(compilation, GetAnalyzers(), AnalyzerOptions); + diagnostics = await cwa.GetAllDiagnosticsAsync().ConfigureAwait(false); + } + return diagnostics.AddRange(hostDiagnostics); } diff --git a/src/Basic.CompilerLog.Util/Impl/BasicAnalyzerHostOnDisk.cs b/src/Basic.CompilerLog.Util/Impl/BasicAnalyzerHostOnDisk.cs index c7774de..fce725b 100644 --- a/src/Basic.CompilerLog.Util/Impl/BasicAnalyzerHostOnDisk.cs +++ b/src/Basic.CompilerLog.Util/Impl/BasicAnalyzerHostOnDisk.cs @@ -131,7 +131,7 @@ internal sealed class OnDiskLoader : IAnalyzerAssemblyLoader, IDisposable { public static readonly DiagnosticDescriptor CannotFindAssembly = new DiagnosticDescriptor( - "BCLA0002", + "BCLA0003", "Cannot find assembly", "Cannot find assembly {0}", "BasicCompilerLog",