Skip to content

Commit f107638

Browse files
gugavaroericstj
andauthored
Adding cmdline flag to validate unused diffs on baseline (#5147)
* Adding cmdline flag to validate unused diffs on baseline * Update src/Microsoft.Cci.Extensions/Filters/BaselineDifferenceFilter.cs Co-Authored-By: Eric StJohn <ericstj@microsoft.com> * Update src/Microsoft.Cci.Extensions/Filters/BaselineDifferenceFilter.cs Co-Authored-By: Eric StJohn <ericstj@microsoft.com> Co-authored-by: Eric StJohn <ericstj@microsoft.com>
1 parent 49a47ee commit f107638

File tree

4 files changed

+54
-12
lines changed

4 files changed

+54
-12
lines changed

src/Microsoft.Cci.Extensions/Filters/BaselineDifferenceFilter.cs

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,24 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
56
using System.Collections.Generic;
67
using System.IO;
8+
using System.Linq;
79
using Microsoft.Cci.Differs;
810

911
namespace Microsoft.Cci.Filters
1012
{
1113
public class BaselineDifferenceFilter : IDifferenceFilter
1214
{
13-
private readonly HashSet<string> _ignoreDifferences = new HashSet<string>();
15+
private readonly Dictionary<string, bool> _ignoreDifferences = new Dictionary<string, bool>();
1416
private readonly IDifferenceFilter _filter;
17+
private readonly bool _treatUnusedDifferencesAsIssues;
1518

16-
public BaselineDifferenceFilter(IDifferenceFilter filter)
19+
public BaselineDifferenceFilter(IDifferenceFilter filter, bool treatUnusedDifferencesAsIssues)
1720
{
1821
_filter = filter;
22+
_treatUnusedDifferencesAsIssues = treatUnusedDifferencesAsIssues;
1923
}
2024

2125
public void AddBaselineFile(string baselineFile)
@@ -35,21 +39,40 @@ public void AddBaselineFile(string baselineFile)
3539
if (string.IsNullOrWhiteSpace(filteredLine))
3640
continue;
3741

38-
_ignoreDifferences.Add(filteredLine);
42+
if (filteredLine.StartsWith("Compat issues with assembly", StringComparison.OrdinalIgnoreCase) ||
43+
filteredLine.StartsWith("Total Issues"))
44+
continue;
45+
46+
_ignoreDifferences[filteredLine] = false;
3947
}
4048
}
4149

4250
public bool Include(Difference difference)
4351
{
4452
// Is the entire rule ignored?
45-
if (_ignoreDifferences.Contains(difference.Id))
53+
if (_ignoreDifferences.ContainsKey(difference.Id))
54+
{
55+
_ignoreDifferences[difference.Id] = true;
4656
return false;
57+
}
4758

4859
// Is the specific violation of the rule ignored?
49-
if (_ignoreDifferences.Contains(difference.ToString()))
60+
var diff = difference.ToString();
61+
if (_ignoreDifferences.ContainsKey(diff))
62+
{
63+
_ignoreDifferences[diff] = true;
5064
return false;
65+
}
5166

5267
return _filter.Include(difference);
5368
}
69+
70+
public IEnumerable<string> GetUnusedBaselineDifferences()
71+
{
72+
if (!_treatUnusedDifferencesAsIssues)
73+
return Enumerable.Empty<string>();
74+
75+
return _ignoreDifferences.Where(i => !i.Value).Select(i => i.Key);
76+
}
5477
}
5578
}

src/Microsoft.Cci.Extensions/Traversers/DifferenceTraverser.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,7 @@ public virtual void Visit(IEnumerable<Difference> differences)
7474
public virtual void Visit(Difference difference)
7575
{
7676
}
77+
78+
protected IDifferenceFilter DifferenceFilter => _filter;
7779
}
7880
}

src/Microsoft.DotNet.ApiCompat/DifferenceWriter.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5+
using System;
56
using System.Collections.Generic;
7+
using System.Composition;
68
using System.Diagnostics;
79
using System.IO;
10+
using System.Linq;
811
using Microsoft.Cci.Differs;
912
using Microsoft.Cci.Filters;
1013
using Microsoft.Cci.Mappings;
1114
using Microsoft.Cci.Traversers;
12-
using System.Composition;
1315

1416
namespace Microsoft.Cci.Writers
1517
{
@@ -45,6 +47,20 @@ public void Write(string oldAssembliesName, IEnumerable<IAssembly> oldAssemblies
4547
}
4648
}
4749

50+
if (DifferenceFilter is BaselineDifferenceFilter filter)
51+
{
52+
var unusedBaselineDifferences = filter.GetUnusedBaselineDifferences();
53+
if (unusedBaselineDifferences.Any())
54+
{
55+
_writer.WriteLine($"{Environment.NewLine}*** Invalid/Unused baseline differences ***");
56+
foreach (var diff in unusedBaselineDifferences)
57+
{
58+
_writer.WriteLine(diff);
59+
_totalDifferences++;
60+
}
61+
}
62+
}
63+
4864
_writer.WriteLine("Total Issues: {0}", _totalDifferences);
4965
_totalDifferences = 0;
5066
}

src/Microsoft.DotNet.ApiCompat/Program.cs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public static int Main(string[] args)
4040
CommandOption implDirs = app.Option("-i|--impl-dirs", "Comma delimited list of directories to find the implementation assemblies for each contract assembly.", CommandOptionType.SingleValue);
4141
implDirs.IsRequired(allowEmptyStrings: true);
4242
CommandOption baseline = app.Option("-b|--baseline", "Comma delimited list of files to skip known diffs.", CommandOptionType.SingleValue);
43+
CommandOption validateBaseline = app.Option("--validate-baseline", "Validates that baseline files don't have invalid/unused diffs.", CommandOptionType.NoValue);
4344
CommandOption mdil = app.Option("-m|--mdil", "Enforce MDIL servicing rules in addition to IL rules.", CommandOptionType.NoValue);
4445
CommandOption outFilePath = app.Option("-o|--out", "Output file path. Default is the console.", CommandOptionType.SingleValue);
4546
CommandOption leftOperand = app.Option("-l|--left-operand", "Name for left operand in comparison, default is 'contract'.", CommandOptionType.SingleValue);
@@ -94,7 +95,7 @@ public static int Main(string[] args)
9495

9596
try
9697
{
97-
BaselineDifferenceFilter filter = GetBaselineDifferenceFilter(HostEnvironment.SplitPaths(baseline.Value()));
98+
BaselineDifferenceFilter filter = GetBaselineDifferenceFilter(HostEnvironment.SplitPaths(baseline.Value()), validateBaseline.HasValue());
9899
NameTable sharedNameTable = new NameTable();
99100
HostEnvironment contractHost = new HostEnvironment(sharedNameTable);
100101
contractHost.UnableToResolve += (sender, e) => Trace.TraceError($"Unable to resolve assembly '{e.Unresolved}' referenced by the {leftOperandValue} assembly '{e.Referrer}'.");
@@ -191,20 +192,20 @@ bool RuleFilter(IDifferenceRuleMetadata ruleMetadata)
191192
Implementation = rightOperand
192193
};
193194
ExportCciSettings.StaticAttributeFilter = GetAttributeFilter(HostEnvironment.SplitPaths(excludeAttributes));
194-
ExportCciSettings.StaticRuleSettings = new RuleSettings { AllowDefaultInterfaceMethods = allowDefaultInterfaceMethods};
195+
ExportCciSettings.StaticRuleSettings = new RuleSettings { AllowDefaultInterfaceMethods = allowDefaultInterfaceMethods };
195196

196197
// Always compose the diff writer to allow it to import or provide exports
197198
container.SatisfyImports(diffWriter);
198199

199200
return diffWriter;
200201
}
201202

202-
private static BaselineDifferenceFilter GetBaselineDifferenceFilter(string[] baselineFileNames)
203+
private static BaselineDifferenceFilter GetBaselineDifferenceFilter(string[] baselineFileNames, bool validateBaseline)
203204
{
204205
BaselineDifferenceFilter baselineDifferenceFilter = null;
205-
206-
AddFiles(baselineFileNames, (file) =>
207-
(baselineDifferenceFilter ??= new BaselineDifferenceFilter(new DifferenceFilter<IncompatibleDifference>())).AddBaselineFile(file));
206+
207+
AddFiles(baselineFileNames, (file) =>
208+
(baselineDifferenceFilter ??= new BaselineDifferenceFilter(new DifferenceFilter<IncompatibleDifference>(), validateBaseline)).AddBaselineFile(file));
208209

209210
return baselineDifferenceFilter;
210211
}

0 commit comments

Comments
 (0)