// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.Diagnostics; namespace ILLink.RoslynAnalyzer.Tests { internal static class TestCaseCompilation { private static readonly ImmutableArray SupportedDiagnosticAnalyzers = ImmutableArray.Create ( new RequiresDynamicCodeAnalyzer (), new COMAnalyzer (), new RequiresAssemblyFilesAnalyzer (), new RequiresUnreferencedCodeAnalyzer (), new DynamicallyAccessedMembersAnalyzer ()); public static Task<(CompilationWithAnalyzers Compilation, SemanticModel SemanticModel, List ExceptionDiagnostics)> CreateCompilation ( string src, (string, string)[]? globalAnalyzerOptions = null, IEnumerable? additionalReferences = null, IEnumerable? additionalSources = null, IEnumerable? additionalFiles = null) => CreateCompilation (CSharpSyntaxTree.ParseText (src), globalAnalyzerOptions, additionalReferences, additionalSources, additionalFiles); public static async Task<(CompilationWithAnalyzers Compilation, SemanticModel SemanticModel, List ExceptionDiagnostics)> CreateCompilation ( SyntaxTree src, (string, string)[]? globalAnalyzerOptions = null, IEnumerable? additionalReferences = null, IEnumerable? additionalSources = null, IEnumerable? additionalFiles = null) { var mdRef = MetadataReference.CreateFromFile (typeof (Mono.Linker.Tests.Cases.Expectations.Metadata.BaseMetadataAttribute).Assembly.Location); additionalReferences ??= Array.Empty (); var sources = new List () { src }; sources.AddRange (additionalSources ?? Array.Empty ()); var comp = CSharpCompilation.Create ( assemblyName: Guid.NewGuid ().ToString ("N"), syntaxTrees: sources, references: (await TestCaseUtils.GetNet6References ()).Add (mdRef).AddRange (additionalReferences), new CSharpCompilationOptions (OutputKind.DynamicallyLinkedLibrary)); var analyzerOptions = new AnalyzerOptions ( additionalFiles: additionalFiles?.ToImmutableArray () ?? ImmutableArray.Empty, new SimpleAnalyzerOptions (globalAnalyzerOptions)); var exceptionDiagnostics = new List (); var compWithAnalyzerOptions = new CompilationWithAnalyzersOptions ( analyzerOptions, (Exception exception, DiagnosticAnalyzer diagnosticAnalyzer, Diagnostic diagnostic) => { exceptionDiagnostics.Add (diagnostic); }, concurrentAnalysis: true, logAnalyzerExecutionTime: false); return (new CompilationWithAnalyzers (comp, SupportedDiagnosticAnalyzers, compWithAnalyzerOptions), comp.GetSemanticModel (src), exceptionDiagnostics); } sealed class SimpleAnalyzerOptions : AnalyzerConfigOptionsProvider { public SimpleAnalyzerOptions ((string, string)[]? globalOptions) { globalOptions ??= Array.Empty<(string, string)> (); GlobalOptions = new SimpleAnalyzerConfigOptions (ImmutableDictionary.CreateRange ( StringComparer.OrdinalIgnoreCase, globalOptions.Select (x => new KeyValuePair (x.Item1, x.Item2)))); } public override AnalyzerConfigOptions GlobalOptions { get; } public override AnalyzerConfigOptions GetOptions (SyntaxTree tree) => SimpleAnalyzerConfigOptions.Empty; public override AnalyzerConfigOptions GetOptions (AdditionalText textFile) => SimpleAnalyzerConfigOptions.Empty; sealed class SimpleAnalyzerConfigOptions : AnalyzerConfigOptions { public static readonly SimpleAnalyzerConfigOptions Empty = new SimpleAnalyzerConfigOptions (ImmutableDictionary.Empty); private readonly ImmutableDictionary _dict; public SimpleAnalyzerConfigOptions (ImmutableDictionary dict) { _dict = dict; } // Suppress warning about missing nullable attributes #pragma warning disable 8765 public override bool TryGetValue (string key, out string? value) => _dict.TryGetValue (key, out value); #pragma warning restore 8765 } } } }