| File: ApiComparer.cs | Web Access |
| Project: src\sdk\src\Compatibility\ApiCompat\Microsoft.DotNet.ApiCompatibility\Microsoft.DotNet.ApiCompatibility.csproj (Microsoft.DotNet.ApiCompatibility) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.CodeAnalysis; using Microsoft.DotNet.ApiCompatibility.Mapping; using Microsoft.DotNet.ApiCompatibility.Rules; namespace Microsoft.DotNet.ApiCompatibility { /// <summary> /// Performs api comparison based on ISymbol inputs. /// </summary> public class ApiComparer : IApiComparer { private readonly IDifferenceVisitorFactory _differenceVisitorFactory; private readonly IElementMapperFactory _elementMapperFactory; /// <inheritdoc /> public ApiComparerSettings Settings { get; } public ApiComparer(IRuleFactory ruleFactory, ApiComparerSettings? settings = null, IDifferenceVisitorFactory? differenceVisitorFactory = null, IRuleContext? ruleContext = null, Func<IRuleFactory, IRuleContext, IRuleRunner>? ruleRunnerFactory = null, Func<IRuleRunner, IElementMapperFactory>? elementMapperFactory = null) { ruleContext ??= new RuleContext(); IRuleRunner ruleRunner = ruleRunnerFactory?.Invoke(ruleFactory, ruleContext) ?? new RuleRunner(ruleFactory, ruleContext); _differenceVisitorFactory = differenceVisitorFactory ?? new DifferenceVisitorFactory(); _elementMapperFactory = elementMapperFactory?.Invoke(ruleRunner) ?? new ElementMapperFactory(ruleRunner); Settings = settings ?? new(); ruleRunner.InitializeRules(Settings); } /// <inheritdoc /> public IEnumerable<CompatDifference> GetDifferences(IAssemblySymbol left, IAssemblySymbol right) { return GetDifferences(new ElementContainer<IAssemblySymbol>(left, MetadataInformation.DefaultLeft), new ElementContainer<IAssemblySymbol>(right, MetadataInformation.DefaultRight)); } /// <inheritdoc /> public IEnumerable<CompatDifference> GetDifferences(ElementContainer<IAssemblySymbol> left, ElementContainer<IAssemblySymbol> right) { IAssemblyMapper assemblyMapper = _elementMapperFactory.CreateAssemblyMapper(Settings, rightCount: 1); assemblyMapper.AddElement(left, ElementSide.Left); assemblyMapper.AddElement(right, ElementSide.Right); IDifferenceVisitor visitor = _differenceVisitorFactory.Create(); visitor.Visit(assemblyMapper); return visitor.CompatDifferences; } /// <inheritdoc /> public IEnumerable<CompatDifference> GetDifferences(IEnumerable<ElementContainer<IAssemblySymbol>> left, IEnumerable<ElementContainer<IAssemblySymbol>> right) { IAssemblySetMapper assemblySetMapper = _elementMapperFactory.CreateAssemblySetMapper(Settings, rightCount: 1); assemblySetMapper.AddElement(left, ElementSide.Left); assemblySetMapper.AddElement(right, ElementSide.Right); IDifferenceVisitor visitor = _differenceVisitorFactory.Create(); visitor.Visit(assemblySetMapper); return visitor.CompatDifferences; } /// <inheritdoc /> public IEnumerable<CompatDifference> GetDifferences(IEnumerable<IAssemblySymbol> left, IEnumerable<IAssemblySymbol> right) { List<ElementContainer<IAssemblySymbol>> transformedLeft = []; foreach (IAssemblySymbol assemblySymbol in left) { transformedLeft.Add(new ElementContainer<IAssemblySymbol>(assemblySymbol, MetadataInformation.DefaultLeft)); } List<ElementContainer<IAssemblySymbol>> transformedRight = []; foreach (IAssemblySymbol assemblySymbol in right) { transformedRight.Add(new ElementContainer<IAssemblySymbol>(assemblySymbol, MetadataInformation.DefaultRight)); } return GetDifferences(transformedLeft, transformedRight); } /// <inheritdoc /> public IEnumerable<CompatDifference> GetDifferences(ElementContainer<IAssemblySymbol> left, IReadOnlyList<ElementContainer<IAssemblySymbol>> right) { int rightCount = right.Count; IAssemblyMapper assemblyMapper = _elementMapperFactory.CreateAssemblyMapper(Settings, rightCount); assemblyMapper.AddElement(left, ElementSide.Left); for (int i = 0; i < rightCount; i++) { assemblyMapper.AddElement(right[i], ElementSide.Right, i); } IDifferenceVisitor visitor = _differenceVisitorFactory.Create(); visitor.Visit(assemblyMapper); return SortCompatDifferencesByInputMetadata(visitor.CompatDifferences.ToLookup(c => c.Right, t => t), right); } /// <inheritdoc /> public IEnumerable<CompatDifference> GetDifferences(IEnumerable<ElementContainer<IAssemblySymbol>> left, IReadOnlyList<IEnumerable<ElementContainer<IAssemblySymbol>>> right) { IAssemblySetMapper assemblySetMapper = _elementMapperFactory.CreateAssemblySetMapper(Settings, right.Count); assemblySetMapper.AddElement(left, ElementSide.Left); for (int rightIndex = 0; rightIndex < right.Count; rightIndex++) { assemblySetMapper.AddElement(right[rightIndex], ElementSide.Right, rightIndex); } IDifferenceVisitor visitor = _differenceVisitorFactory.Create(); visitor.Visit(assemblySetMapper); return SortCompatDifferencesByInputMetadata(visitor.CompatDifferences.ToLookup(c => c.Left, t => t), left); } // Sort the compat differences by the order of the passed in metadata. private static List<CompatDifference> SortCompatDifferencesByInputMetadata(ILookup<MetadataInformation, CompatDifference> compatDifferencesLookup, IEnumerable<ElementContainer<IAssemblySymbol>> inputMetadata) { HashSet<MetadataInformation> processedMetadata = []; List<CompatDifference> sortedCompatDifferences = []; foreach (ElementContainer<IAssemblySymbol> elementContainer in inputMetadata) { sortedCompatDifferences.AddRange(compatDifferencesLookup[elementContainer.MetadataInformation]); processedMetadata.Add(elementContainer.MetadataInformation); } foreach (IGrouping<MetadataInformation, CompatDifference> compatDifferenceGroup in compatDifferencesLookup) { if (processedMetadata.Contains(compatDifferenceGroup.Key)) continue; sortedCompatDifferences.AddRange(compatDifferenceGroup); } return sortedCompatDifferences; } } }