| File: Linker\WarningSuppressionWriter.cs | Web Access |
| Project: src\runtime\src\tools\illink\src\linker\Mono.Linker.csproj (illink) |
// 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.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Xml; using System.Xml.Linq; using Mono.Cecil; namespace Mono.Linker { public class WarningSuppressionWriter { private readonly Dictionary<AssemblyNameDefinition, HashSet<(int Code, IMemberDefinition Member)>> _warnings; private readonly FileOutputKind _fileOutputKind; readonly LinkContext _context; public WarningSuppressionWriter(LinkContext context, FileOutputKind fileOutputKind = FileOutputKind.CSharp) { _warnings = new Dictionary<AssemblyNameDefinition, HashSet<(int, IMemberDefinition)>>(); _fileOutputKind = fileOutputKind; _context = context; } public bool IsEmpty => _warnings.Count == 0; public void AddWarning(int code, ICustomAttributeProvider provider) { // We don't have a targeted suppression mechanism for // warnings from assembly-level attributes. if (provider is not IMemberDefinition memberDefinition) return; if (UnconditionalSuppressMessageAttributeState.GetModuleFromProvider(provider) is not ModuleDefinition module) return; var assemblyName = module.Assembly.Name; if (!_warnings.TryGetValue(assemblyName, out var warnings)) { warnings = new HashSet<(int, IMemberDefinition)>(); _warnings.Add(assemblyName, warnings); } warnings.Add((code, memberDefinition)); } public void OutputSuppressions(string directory) { foreach (var assemblyName in _warnings.Keys) { if (_fileOutputKind == FileOutputKind.Xml) { OutputSuppressionsXmlFormat(assemblyName, directory); } else { OutputSuppressionsCSharpFormat(assemblyName, directory); } } } void OutputSuppressionsXmlFormat(AssemblyNameDefinition assemblyName, string directory) { var xmlTree = new XElement("linker"); var xmlAssembly = new XElement("assembly", new XAttribute("fullname", assemblyName.FullName)); xmlTree.Add(xmlAssembly); foreach (var warning in GetListOfWarnings(assemblyName)) { xmlAssembly.Add( new XElement("attribute", new XAttribute("fullname", "System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute"), new XElement("argument", Constants.ILLink), new XElement("argument", $"IL{warning.Code}"), new XElement("property", new XAttribute("name", UnconditionalSuppressMessageAttributeState.ScopeProperty), GetWarningSuppressionScopeString(warning.MemberDocumentationSignature)), new XElement("property", new XAttribute("name", UnconditionalSuppressMessageAttributeState.TargetProperty), warning.MemberDocumentationSignature))); } XDocument xdoc = new XDocument(xmlTree); using (var xw = XmlWriter.Create(Path.Combine(directory, $"{assemblyName.Name}.WarningSuppressions.xml"), new XmlWriterSettings { Indent = true })) { xdoc.Save(xw); } } void OutputSuppressionsCSharpFormat(AssemblyNameDefinition assemblyName, string directory) { using (var sw = new StreamWriter(Path.Combine(directory, $"{assemblyName.Name}.WarningSuppressions.cs"))) { StringBuilder sb = new StringBuilder("using System.Diagnostics.CodeAnalysis;").AppendLine().AppendLine(); foreach (var warning in GetListOfWarnings(assemblyName)) { sb.Append("[assembly: UnconditionalSuppressMessage(\"") .Append(Constants.ILLink) .Append("\", \"IL").Append(warning.Code) .Append("\", Scope = \"").Append(GetWarningSuppressionScopeString(warning.MemberDocumentationSignature)) .Append("\", Target = \"").Append(warning.MemberDocumentationSignature) .AppendLine("\")]"); } sw.Write(sb.ToString()); } } List<(int Code, string MemberDocumentationSignature)> GetListOfWarnings(AssemblyNameDefinition assemblyName) { List<(int Code, string MemberDocumentationSignature)> listOfWarnings = new List<(int Code, string MemberDocumentationSignature)>(); StringBuilder sb = new StringBuilder(); foreach (var warning in _warnings[assemblyName].ToList()) { DocumentationSignatureGenerator.VisitMember(warning.Member, sb, _context); listOfWarnings.Add((warning.Code, sb.ToString())); sb.Clear(); } listOfWarnings.Sort(); return listOfWarnings; } static string GetWarningSuppressionScopeString(string memberDocumentationSignature) { if (memberDocumentationSignature.StartsWith(DocumentationSignatureGenerator.TypePrefix)) return "type"; return "member"; } public enum FileOutputKind { CSharp, Xml }; } }