From 22800b05d274f7343d4412fcd7b32f22a918d131 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:34:46 -0800 Subject: [PATCH 01/12] Allow creating symbol filters from files or from lists more clearly, both for Attribute filtering or for API filtering. --- .../Filtering/DocIdSymbolFilter.cs | 44 ++++++++--- .../Filtering/SymbolFilterFactory.cs | 76 +++++++++++++++++++ 2 files changed, 109 insertions(+), 11 deletions(-) create mode 100644 src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs diff --git a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs index 3bb8ba16fac6..0e9939453d2a 100644 --- a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs +++ b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs @@ -9,9 +9,18 @@ namespace Microsoft.DotNet.ApiSymbolExtensions.Filtering /// Implements the logic of filtering out api. /// Reads the file with the list of attributes, types, members in DocId format. /// - public class DocIdSymbolFilter(string[] docIdsToExcludeFiles) : ISymbolFilter + public class DocIdSymbolFilter : ISymbolFilter { - private readonly HashSet _docIdsToExclude = new(ReadDocIdsAttributes(docIdsToExcludeFiles)); + private readonly HashSet _docIdsToExclude; + + public static DocIdSymbolFilter CreateFromFiles(params string[] filesWithDocIdsToExclude) + => new DocIdSymbolFilter(ReadDocIdsFromFiles(filesWithDocIdsToExclude)); + + public static DocIdSymbolFilter CreateFromLists(params string[] docIdsToExclude) + => new DocIdSymbolFilter(ReadDocIdsFromList(docIdsToExclude)); + + private DocIdSymbolFilter(IEnumerable docIdsToExclude) + => _docIdsToExclude = [.. docIdsToExclude]; /// /// Determines whether the should be included. @@ -29,20 +38,33 @@ public bool Include(ISymbol symbol) return true; } - private static IEnumerable ReadDocIdsAttributes(IEnumerable docIdsToExcludeFiles) + private static IEnumerable ReadDocIdsFromList(params string[] ids) { - foreach (string docIdsToExcludeFile in docIdsToExcludeFiles) + foreach (string id in ids) { - foreach (string id in File.ReadAllLines(docIdsToExcludeFile)) - { #if NET - if (!string.IsNullOrWhiteSpace(id) && !id.StartsWith('#') && !id.StartsWith("//")) + if (!string.IsNullOrWhiteSpace(id) && !id.StartsWith('#') && !id.StartsWith("//")) #else - if (!string.IsNullOrWhiteSpace(id) && !id.StartsWith("#") && !id.StartsWith("//")) + if (!string.IsNullOrWhiteSpace(id) && !id.StartsWith("#") && !id.StartsWith("//")) #endif - { - yield return id.Trim(); - } + { + yield return id.Trim(); + } + } + } + + private static IEnumerable ReadDocIdsFromFiles(params string[] docIdsToExcludeFiles) + { + foreach (string docIdsToExcludeFile in docIdsToExcludeFiles) + { + if (string.IsNullOrWhiteSpace(docIdsToExcludeFile)) + { + continue; + } + + foreach (string docId in ReadDocIdsFromList(File.ReadAllLines(docIdsToExcludeFile))) + { + yield return docId; } } } diff --git a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs new file mode 100644 index 000000000000..6bfede00f550 --- /dev/null +++ b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs @@ -0,0 +1,76 @@ +// 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; + +namespace Microsoft.DotNet.ApiSymbolExtensions.Filtering; + +public static class SymbolFilterFactory +{ + /// + /// Creates a composite filter to exclude APIs using the DocIDs provided in the specifed file paths. + /// + /// A collection of paths where the exclusion files should be searched. + /// Whether to include internal symbols or not. + /// Whether to include effectively private symbols or not. + /// Whether to include explicit interface implementation symbols or not. + /// An instance of the symbol filter. + public static ISymbolFilter GetFilterFromFiles(string[]? apiExclusionFilePaths, + bool respectInternals = false, + bool includeEffectivelyPrivateSymbols = true, + bool includeExplicitInterfaceImplementationSymbols = true) + { + DocIdSymbolFilter? docIdSymbolFilter = + apiExclusionFilePaths?.Count() > 0 ? + DocIdSymbolFilter.CreateFromFiles(apiExclusionFilePaths) : null; + + return GetCompositeSymbolFilter(docIdSymbolFilter, respectInternals, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols, withImplicitSymbolFilter: true); + } + + /// + /// Creates a composite filter to exclude APIs using the DocIDs provided in the specifed list. + /// + /// A collection of exclusion list. + /// Whether to include internal symbols or not. + /// Whether to include effectively private symbols or not. + /// Whether to include explicit interface implementation symbols or not. + /// An instance of the symbol filter. + public static ISymbolFilter GetFilterFromList(string[]? apiExclusionList, + bool respectInternals = false, + bool includeEffectivelyPrivateSymbols = true, + bool includeExplicitInterfaceImplementationSymbols = true) + { + DocIdSymbolFilter? docIdSymbolFilter = + apiExclusionList?.Count() > 0 ? + DocIdSymbolFilter.CreateFromLists(apiExclusionList) : null; + + return GetCompositeSymbolFilter(docIdSymbolFilter, respectInternals, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols, withImplicitSymbolFilter: true); + } + + private static ISymbolFilter GetCompositeSymbolFilter(DocIdSymbolFilter? customFilter, + bool respectInternals, + bool includeEffectivelyPrivateSymbols, + bool includeExplicitInterfaceImplementationSymbols, + bool withImplicitSymbolFilter) + { + AccessibilitySymbolFilter accessibilitySymbolFilter = new( + respectInternals, + includeEffectivelyPrivateSymbols, + includeExplicitInterfaceImplementationSymbols); + + CompositeSymbolFilter filter = new(); + + if (customFilter != null) + { + filter.Add(customFilter); + } + if (withImplicitSymbolFilter) + { + filter.Add(new ImplicitSymbolFilter()); + } + + filter.Add(accessibilitySymbolFilter); + + return filter; + } +} From e9c29aa98aa6599a0bb72be22de8a979a27af2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:42:35 -0800 Subject: [PATCH 02/12] Update src places where symbol filtering is currently used. --- .../ApiCompatServiceProvider.cs | 13 ++---------- .../Microsoft.DotNet.GenAPI/GenAPIApp.cs | 20 ++----------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs b/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs index 4edb495c0e5d..d2383b7883b4 100644 --- a/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs +++ b/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs @@ -27,21 +27,12 @@ public ApiCompatServiceProvider(Func logFa _compatibilityLogger = new Lazy(() => logFactory(SuppressionEngine)); _apiCompatRunner = new Lazy(() => { - AccessibilitySymbolFilter accessibilitySymbolFilter = new(respectInternals); SymbolEqualityComparer symbolEqualityComparer = new(); - // The attribute data symbol filter is a composite that contains both the accessibility - // symbol filter and the doc id symbol filter. - CompositeSymbolFilter attributeDataSymbolFilter = new(accessibilitySymbolFilter); - if (excludeAttributesFiles is not null) - { - attributeDataSymbolFilter.Add(new DocIdSymbolFilter(excludeAttributesFiles)); - } - ApiComparerSettings apiComparerSettings = new( - accessibilitySymbolFilter, + symbolFilter: null, // Gets a default value inside the constructor symbolEqualityComparer, - attributeDataSymbolFilter, + SymbolFilterFactory.GetFilterFromFiles(excludeAttributesFiles, respectInternals), new AttributeDataEqualityComparer(symbolEqualityComparer, new TypedConstantEqualityComparer(symbolEqualityComparer)), respectInternals); diff --git a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/GenAPIApp.cs b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/GenAPIApp.cs index f537d26e823b..20b34a523629 100644 --- a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/GenAPIApp.cs +++ b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/GenAPIApp.cs @@ -48,22 +48,6 @@ public static void Run(ILog log, includeEffectivelyPrivateSymbols: true, includeExplicitInterfaceImplementationSymbols: true); - // Configure the symbol filter - CompositeSymbolFilter symbolFilter = new(); - if (excludeApiFiles is not null) - { - symbolFilter.Add(new DocIdSymbolFilter(excludeApiFiles)); - } - symbolFilter.Add(new ImplicitSymbolFilter()); - symbolFilter.Add(accessibilitySymbolFilter); - - // Configure the attribute data symbol filter - CompositeSymbolFilter attributeDataSymbolFilter = new(); - if (excludeAttributesFiles is not null) - { - attributeDataSymbolFilter.Add(new DocIdSymbolFilter(excludeAttributesFiles)); - } - attributeDataSymbolFilter.Add(accessibilitySymbolFilter); // Invoke the CSharpFileBuilder for each directly loaded assembly. foreach (IAssemblySymbol? assemblySymbol in assemblySymbols) @@ -75,8 +59,8 @@ public static void Run(ILog log, textWriter.Write(headerFileText); using CSharpFileBuilder fileBuilder = new(log, - symbolFilter, - attributeDataSymbolFilter, + SymbolFilterFactory.GetFilterFromFiles(excludeApiFiles, respectInternals), + SymbolFilterFactory.GetFilterFromFiles(excludeAttributesFiles, respectInternals), textWriter, exceptionMessage, includeAssemblyAttributes, From 4fcb4a75a0550e641506a653b68ead593d286ede Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Thu, 23 Jan 2025 16:42:44 -0800 Subject: [PATCH 03/12] Update test places where symbol filtering is used. --- ...osoft.DotNet.ApiCompatibility.Tests.csproj | 1 + .../Rules/AttributesMustMatchTests.cs | 79 +++++++++---------- .../CSharpFileBuilderTests.cs | 29 +------ 3 files changed, 43 insertions(+), 66 deletions(-) diff --git a/test/Microsoft.DotNet.ApiCompatibility.Tests/Microsoft.DotNet.ApiCompatibility.Tests.csproj b/test/Microsoft.DotNet.ApiCompatibility.Tests/Microsoft.DotNet.ApiCompatibility.Tests.csproj index e2c0ccd07842..b7ef947259e9 100644 --- a/test/Microsoft.DotNet.ApiCompatibility.Tests/Microsoft.DotNet.ApiCompatibility.Tests.csproj +++ b/test/Microsoft.DotNet.ApiCompatibility.Tests/Microsoft.DotNet.ApiCompatibility.Tests.csproj @@ -17,6 +17,7 @@ + diff --git a/test/Microsoft.DotNet.ApiCompatibility.Tests/Rules/AttributesMustMatchTests.cs b/test/Microsoft.DotNet.ApiCompatibility.Tests/Rules/AttributesMustMatchTests.cs index 11d9b98aea4f..993a6b98cabf 100644 --- a/test/Microsoft.DotNet.ApiCompatibility.Tests/Rules/AttributesMustMatchTests.cs +++ b/test/Microsoft.DotNet.ApiCompatibility.Tests/Rules/AttributesMustMatchTests.cs @@ -20,7 +20,7 @@ public class AttributesMustMatchTests * - ReturnValues * - Constructors * - Generic Parameters - * + * * Grouped into: * - Type * - Member @@ -28,9 +28,6 @@ public class AttributesMustMatchTests private static readonly TestRuleFactory s_ruleFactory = new((settings, context) => new AttributesMustMatch(settings, context)); - private static ISymbolFilter GetAccessibilityAndAttributeSymbolFiltersAsComposite(params string[] excludeAttributeFiles) => - new CompositeSymbolFilter().Add(new AccessibilitySymbolFilter(false)).Add(new DocIdSymbolFilter(excludeAttributeFiles)); - public static TheoryData TypesCases => new() { // No change to type's attributes @@ -39,7 +36,7 @@ private static ISymbolFilter GetAccessibilityAndAttributeSymbolFiltersAsComposit namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -56,7 +53,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -77,7 +74,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -94,7 +91,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -116,7 +113,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -133,7 +130,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -156,7 +153,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -173,7 +170,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -196,7 +193,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -212,7 +209,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -311,7 +308,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -337,7 +334,7 @@ public void F() {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -370,7 +367,7 @@ public void F() {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -396,7 +393,7 @@ public class First { namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -429,7 +426,7 @@ public class First { namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -457,7 +454,7 @@ public class First { namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -492,7 +489,7 @@ public class First { namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -518,7 +515,7 @@ public First() {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -551,7 +548,7 @@ public First() {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -577,7 +574,7 @@ public class First { namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -610,7 +607,7 @@ public class First { namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -634,7 +631,7 @@ public void F([Bar] int v, [Foo(""S"", A = true, B = 0)] string s) {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -666,7 +663,7 @@ public void F([Baz] int v, [Foo(""T"")] string s) {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -687,7 +684,7 @@ public class First<[Bar] T1, [Foo(""S"", A = true, B = 0)] T2> {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -716,7 +713,7 @@ public class First<[Baz] T1, [Foo(""T"")] T2> {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -740,7 +737,7 @@ public class First { namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -792,7 +789,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -815,7 +812,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -832,7 +829,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -1332,7 +1329,7 @@ public void EnsureDiagnosticIsReported(string leftSyntax, string rightSyntax, Co IAssemblySymbol left = SymbolFactory.GetAssemblyFromSyntax(leftSyntax); IAssemblySymbol right = SymbolFactory.GetAssemblyFromSyntax(rightSyntax); ApiComparer differ = new(s_ruleFactory); - differ.Settings.AttributeDataSymbolFilter = GetAccessibilityAndAttributeSymbolFiltersAsComposite(filePath); + differ.Settings.AttributeDataSymbolFilter = SymbolFilterFactory.GetFilterFromFiles([filePath], respectInternals: false); IEnumerable actual = differ.GetDifferences(left, right); @@ -1349,7 +1346,7 @@ public void EnsureStrictModeReported(string leftSyntax, string rightSyntax, Comp IAssemblySymbol left = SymbolFactory.GetAssemblyFromSyntax(leftSyntax); IAssemblySymbol right = SymbolFactory.GetAssemblyFromSyntax(rightSyntax); ApiComparer differ = new(s_ruleFactory, new ApiComparerSettings(strictMode: true)); - differ.Settings.AttributeDataSymbolFilter = GetAccessibilityAndAttributeSymbolFiltersAsComposite(filePath); + differ.Settings.AttributeDataSymbolFilter = SymbolFilterFactory.GetFilterFromFiles([filePath], respectInternals: false); IEnumerable actual = differ.GetDifferences(left, right); @@ -1366,7 +1363,7 @@ public void TestExclusionsFilteredOut() namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -1382,7 +1379,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -1398,7 +1395,7 @@ public class First {} IAssemblySymbol left = SymbolFactory.GetAssemblyFromSyntax(leftSyntax); IAssemblySymbol right = SymbolFactory.GetAssemblyFromSyntax(rightSyntax); ApiComparer differ = new(s_ruleFactory); - differ.Settings.AttributeDataSymbolFilter = GetAccessibilityAndAttributeSymbolFiltersAsComposite(filePath); + differ.Settings.AttributeDataSymbolFilter = SymbolFilterFactory.GetFilterFromFiles([filePath], respectInternals: false); IEnumerable actual = differ.GetDifferences(left, right); @@ -1418,7 +1415,7 @@ public void AttributesExcludedButMembersValidated() namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -1433,7 +1430,7 @@ public class First {} namespace CompatTests { using System; - + [AttributeUsage(AttributeTargets.All, AllowMultiple = true)] public class FooAttribute : Attribute { public FooAttribute(String s) {} @@ -1448,7 +1445,7 @@ public class First {} IAssemblySymbol left = SymbolFactory.GetAssemblyFromSyntax(leftSyntax); IAssemblySymbol right = SymbolFactory.GetAssemblyFromSyntax(rightSyntax); ApiComparer differ = new(ruleFactory, new ApiComparerSettings(strictMode: true)); - differ.Settings.AttributeDataSymbolFilter = GetAccessibilityAndAttributeSymbolFiltersAsComposite(filePath); + differ.Settings.AttributeDataSymbolFilter = SymbolFilterFactory.GetFilterFromFiles([filePath], respectInternals: false); IEnumerable actual = differ.GetDifferences(left, right).ToArray(); diff --git a/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs b/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs index 81856d2842ce..6c8fd9af98de 100644 --- a/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs +++ b/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs @@ -32,34 +32,17 @@ private void RunTest(string original, bool includeEffectivelyPrivateSymbols = true, bool includeExplicitInterfaceImplementationSymbols = true, bool allowUnsafe = false, - string excludedAttributeFile = null, + string[] excludedAttributeList = null, [CallerMemberName] string assemblyName = "") { StringWriter stringWriter = new(); - // Configure symbol filters - AccessibilitySymbolFilter accessibilitySymbolFilter = new( - includeInternalSymbols, - includeEffectivelyPrivateSymbols, - includeExplicitInterfaceImplementationSymbols); - - CompositeSymbolFilter symbolFilter = new CompositeSymbolFilter() - .Add(new ImplicitSymbolFilter()) - .Add(accessibilitySymbolFilter); - - CompositeSymbolFilter attributeDataSymbolFilter = new(); - if (excludedAttributeFile is not null) - { - attributeDataSymbolFilter.Add(new DocIdSymbolFilter(new string[] { excludedAttributeFile })); - } - attributeDataSymbolFilter.Add(accessibilitySymbolFilter); - Mock log = new(); IAssemblySymbolWriter csharpFileBuilder = new CSharpFileBuilder( log.Object, - symbolFilter, - attributeDataSymbolFilter, + SymbolFilterFactory.GetFilterFromList([], includeInternalSymbols, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols), + SymbolFilterFactory.GetFilterFromList(excludedAttributeList ?? [], includeInternalSymbols, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols), stringWriter, null, false, @@ -2764,10 +2747,6 @@ public class PublicClass { } [Fact] public void TestAttributesExcludedWithFilter() { - using TempDirectory root = new(); - string filePath = Path.Combine(root.DirPath, "exclusions.txt"); - File.WriteAllText(filePath, "T:A.AnyTestAttribute"); - RunTest(original: """ namespace A { @@ -2803,7 +2782,7 @@ public partial class PublicClass } """, includeInternalSymbols: false, - excludedAttributeFile: filePath); + excludedAttributeList: ["T:A.AnyTestAttribute"]); } [Fact] From c9190fc751bc4d310277852a2b24b22ab339d30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:43:54 -0800 Subject: [PATCH 04/12] Remove unnecesary ProjectReference --- .../Microsoft.DotNet.ApiCompatibility.Tests.csproj | 1 - 1 file changed, 1 deletion(-) diff --git a/test/Microsoft.DotNet.ApiCompatibility.Tests/Microsoft.DotNet.ApiCompatibility.Tests.csproj b/test/Microsoft.DotNet.ApiCompatibility.Tests/Microsoft.DotNet.ApiCompatibility.Tests.csproj index b7ef947259e9..e2c0ccd07842 100644 --- a/test/Microsoft.DotNet.ApiCompatibility.Tests/Microsoft.DotNet.ApiCompatibility.Tests.csproj +++ b/test/Microsoft.DotNet.ApiCompatibility.Tests/Microsoft.DotNet.ApiCompatibility.Tests.csproj @@ -17,7 +17,6 @@ - From 493beff5f78686dbdf98d63f52882cb32b209d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:06:21 -0800 Subject: [PATCH 05/12] Inline private method in DocIdSymbolFilter and document public APIs. --- .../Filtering/DocIdSymbolFilter.cs | 45 ++++++++++++------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs index 0e9939453d2a..a550cb5b02e2 100644 --- a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs +++ b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs @@ -13,12 +13,40 @@ public class DocIdSymbolFilter : ISymbolFilter { private readonly HashSet _docIdsToExclude; + /// + /// Creates a filter to exclude APIs using the DocIDs provided in the specified files. + /// + /// A collection of files each containing multiple DocIDs to exclude. + /// An instance of the symbol filter. public static DocIdSymbolFilter CreateFromFiles(params string[] filesWithDocIdsToExclude) - => new DocIdSymbolFilter(ReadDocIdsFromFiles(filesWithDocIdsToExclude)); + { + List docIds = new(); + + foreach (string docIdsToExcludeFile in filesWithDocIdsToExclude) + { + if (string.IsNullOrWhiteSpace(docIdsToExcludeFile)) + { + continue; + } + + foreach (string docId in ReadDocIdsFromList(File.ReadAllLines(docIdsToExcludeFile))) + { + docIds.Add(docId); + } + } + + return new DocIdSymbolFilter(docIds); + } + /// + /// Creates a filter to exclude APIs using the DocIDs provided in the specified list. + /// + /// A collection of DocIDs to exclude. + /// An instance of the symbol filter. public static DocIdSymbolFilter CreateFromLists(params string[] docIdsToExclude) => new DocIdSymbolFilter(ReadDocIdsFromList(docIdsToExclude)); + // Private constructor to avoid creating an instance with an empty list. private DocIdSymbolFilter(IEnumerable docIdsToExclude) => _docIdsToExclude = [.. docIdsToExclude]; @@ -53,20 +81,5 @@ private static IEnumerable ReadDocIdsFromList(params string[] ids) } } - private static IEnumerable ReadDocIdsFromFiles(params string[] docIdsToExcludeFiles) - { - foreach (string docIdsToExcludeFile in docIdsToExcludeFiles) - { - if (string.IsNullOrWhiteSpace(docIdsToExcludeFile)) - { - continue; - } - - foreach (string docId in ReadDocIdsFromList(File.ReadAllLines(docIdsToExcludeFile))) - { - yield return docId; - } - } - } } } From ce6e15bb389a083754d5295afb346756e5e941cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:16:04 -0800 Subject: [PATCH 06/12] Triple slash for SymbolFilterFactory. --- .../Filtering/SymbolFilterFactory.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs index 6bfede00f550..6207c4ab90d2 100644 --- a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs +++ b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs @@ -5,6 +5,9 @@ namespace Microsoft.DotNet.ApiSymbolExtensions.Filtering; +/// +/// A factory class to create symbol filters. +/// public static class SymbolFilterFactory { /// From 76e959b53484a3147e8603636fd80ca818d1c923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Fri, 24 Jan 2025 13:17:22 -0800 Subject: [PATCH 07/12] nit --- .../Filtering/DocIdSymbolFilter.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs index a550cb5b02e2..9bd20dd20b6d 100644 --- a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs +++ b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/DocIdSymbolFilter.cs @@ -80,6 +80,5 @@ private static IEnumerable ReadDocIdsFromList(params string[] ids) } } } - } } From 9198d3dccae82e62db9a6981e4912b9f9bf46d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 27 Jan 2025 13:36:25 -0800 Subject: [PATCH 08/12] Add symbol filter factory tests --- .../SymbolFilterFactoryTests.cs | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 test/Microsoft.DotNet.ApiSymbolExtensions.Tests/SymbolFilterFactoryTests.cs diff --git a/test/Microsoft.DotNet.ApiSymbolExtensions.Tests/SymbolFilterFactoryTests.cs b/test/Microsoft.DotNet.ApiSymbolExtensions.Tests/SymbolFilterFactoryTests.cs new file mode 100644 index 000000000000..7c8e78e99827 --- /dev/null +++ b/test/Microsoft.DotNet.ApiSymbolExtensions.Tests/SymbolFilterFactoryTests.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#nullable disable + +using Xunit; +using Microsoft.DotNet.ApiSymbolExtensions.Filtering; +using Microsoft.CodeAnalysis; + +namespace Microsoft.DotNet.ApiSymbolExtensions.Tests; + +public class SymbolFilterFactoryTests +{ + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Test_FilterFromFiles(bool includeCustomType) + { + using TempDirectory root = new(); + string filePath = Path.Combine(root.DirPath, "exclusions.txt"); + using (FileStream fileStream = File.Create(filePath)) + { + using StreamWriter writer = new(fileStream); + writer.WriteLine("T:System.Int32"); + writer.WriteLine("T:System.String"); + if (!includeCustomType) + { + writer.WriteLine("T:MyNamespace.MyClass"); + } + } + + CompositeSymbolFilter filter = SymbolFilterFactory.GetFilterFromFiles( + apiExclusionFilePaths: [filePath], + respectInternals: true, + includeEffectivelyPrivateSymbols: true, + includeExplicitInterfaceImplementationSymbols: true) as CompositeSymbolFilter; + + Test_GetFilter_Internal(filter, includeCustomType); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Test_FilterFromList(bool includeCustomType) + { + List exclusions = ["T:System.Int32", "T:System.String"]; + if (!includeCustomType) + { + exclusions.Add("T:MyNamespace.MyClass"); + } + + CompositeSymbolFilter filter = SymbolFilterFactory.GetFilterFromList( + apiExclusionList: exclusions.ToArray(), + respectInternals: true, + includeEffectivelyPrivateSymbols: true, + includeExplicitInterfaceImplementationSymbols: true) as CompositeSymbolFilter; + + Test_GetFilter_Internal(filter, includeCustomType); + } + + private void Test_GetFilter_Internal(CompositeSymbolFilter filter, bool includeCustomType) + { + Assert.NotNull(filter); + + Assert.Equal(3, filter.Filters.Count); + + DocIdSymbolFilter docIdFilter = filter.Filters[0] as DocIdSymbolFilter; + Assert.NotNull(docIdFilter); + + ImplicitSymbolFilter implicitFilter = filter.Filters[1] as ImplicitSymbolFilter; + Assert.NotNull(implicitFilter); + + AccessibilitySymbolFilter accessibilityFilter = filter.Filters[2] as AccessibilitySymbolFilter; + Assert.NotNull(accessibilityFilter); + + IAssemblySymbol assemblySymbol = SymbolFactory.GetAssemblyFromSyntax(@" +namespace MyNamespace +{ + public class MyClass { } +}"); + Assert.NotNull(assemblySymbol); + INamedTypeSymbol myClass = assemblySymbol.GetTypeByMetadataName("MyNamespace.MyClass"); + Assert.NotNull(myClass); + Assert.Equal(includeCustomType, docIdFilter.Include(myClass)); + } +} From 6bb3f1ae9a8c5331a699a3832d60b91fdc966d48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 27 Jan 2025 15:03:12 -0800 Subject: [PATCH 09/12] count() -> length --- .../Filtering/SymbolFilterFactory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs index 6207c4ab90d2..11211e9652a8 100644 --- a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs +++ b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs @@ -24,7 +24,7 @@ public static ISymbolFilter GetFilterFromFiles(string[]? apiExclusionFilePaths, bool includeExplicitInterfaceImplementationSymbols = true) { DocIdSymbolFilter? docIdSymbolFilter = - apiExclusionFilePaths?.Count() > 0 ? + apiExclusionFilePaths?.Length > 0 ? DocIdSymbolFilter.CreateFromFiles(apiExclusionFilePaths) : null; return GetCompositeSymbolFilter(docIdSymbolFilter, respectInternals, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols, withImplicitSymbolFilter: true); From bd8079a500f5da265953b1f78ddb28231fa331bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 27 Jan 2025 16:40:29 -0800 Subject: [PATCH 10/12] Named parameters for readability --- .../ApiCompatServiceProvider.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs b/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs index d2383b7883b4..358283465453 100644 --- a/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs +++ b/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs @@ -29,13 +29,15 @@ public ApiCompatServiceProvider(Func logFa { SymbolEqualityComparer symbolEqualityComparer = new(); + ISymbolFilter attributeDataSymbolFilter = SymbolFilterFactory.GetFilterFromFiles(excludeAttributesFiles, respectInternals); + AttributeDataEqualityComparer attributeDataEqualityComparer = new(symbolEqualityComparer, + new TypedConstantEqualityComparer(symbolEqualityComparer)); + ApiComparerSettings apiComparerSettings = new( - symbolFilter: null, // Gets a default value inside the constructor - symbolEqualityComparer, - SymbolFilterFactory.GetFilterFromFiles(excludeAttributesFiles, respectInternals), - new AttributeDataEqualityComparer(symbolEqualityComparer, - new TypedConstantEqualityComparer(symbolEqualityComparer)), - respectInternals); + symbolEqualityComparer: symbolEqualityComparer, + attributeDataSymbolFilter: attributeDataSymbolFilter, + attributeDataEqualityComparer: attributeDataEqualityComparer, + includeInternalSymbols: respectInternals); return new ApiCompatRunner(SuppressibleLog, SuppressionEngine, From 731117d8808391a6e080372d246655eea34c04a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Mon, 27 Jan 2025 17:04:24 -0800 Subject: [PATCH 11/12] Add an optional accessibility symbol filter argument to symbol filter factory methods. --- .../ApiCompatServiceProvider.cs | 8 +++- .../Microsoft.DotNet.GenAPI/GenAPIApp.cs | 4 +- .../Filtering/SymbolFilterFactory.cs | 37 ++++++++------ .../SymbolFilterFactoryTests.cs | 48 +++++++++++++++---- 4 files changed, 70 insertions(+), 27 deletions(-) diff --git a/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs b/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs index 358283465453..6d51ecc24a23 100644 --- a/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs +++ b/src/Compatibility/ApiCompat/Microsoft.DotNet.ApiCompat.Shared/ApiCompatServiceProvider.cs @@ -27,13 +27,19 @@ public ApiCompatServiceProvider(Func logFa _compatibilityLogger = new Lazy(() => logFactory(SuppressionEngine)); _apiCompatRunner = new Lazy(() => { + AccessibilitySymbolFilter accessibilitySymbolFilter = new(respectInternals); SymbolEqualityComparer symbolEqualityComparer = new(); - ISymbolFilter attributeDataSymbolFilter = SymbolFilterFactory.GetFilterFromFiles(excludeAttributesFiles, respectInternals); + ISymbolFilter attributeDataSymbolFilter = SymbolFilterFactory.GetFilterFromFiles( + apiExclusionFilePaths: excludeAttributesFiles, + accessibilitySymbolFilter: accessibilitySymbolFilter, + respectInternals: respectInternals); + AttributeDataEqualityComparer attributeDataEqualityComparer = new(symbolEqualityComparer, new TypedConstantEqualityComparer(symbolEqualityComparer)); ApiComparerSettings apiComparerSettings = new( + symbolFilter: accessibilitySymbolFilter, symbolEqualityComparer: symbolEqualityComparer, attributeDataSymbolFilter: attributeDataSymbolFilter, attributeDataEqualityComparer: attributeDataEqualityComparer, diff --git a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/GenAPIApp.cs b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/GenAPIApp.cs index 20b34a523629..0d82dd24e4c4 100644 --- a/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/GenAPIApp.cs +++ b/src/Compatibility/GenAPI/Microsoft.DotNet.GenAPI/GenAPIApp.cs @@ -59,8 +59,8 @@ public static void Run(ILog log, textWriter.Write(headerFileText); using CSharpFileBuilder fileBuilder = new(log, - SymbolFilterFactory.GetFilterFromFiles(excludeApiFiles, respectInternals), - SymbolFilterFactory.GetFilterFromFiles(excludeAttributesFiles, respectInternals), + SymbolFilterFactory.GetFilterFromFiles(excludeApiFiles, respectInternals: respectInternals), + SymbolFilterFactory.GetFilterFromFiles(excludeAttributesFiles, respectInternals: respectInternals), textWriter, exceptionMessage, includeAssemblyAttributes, diff --git a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs index 11211e9652a8..18ea253e5368 100644 --- a/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs +++ b/src/Compatibility/Microsoft.DotNet.ApiSymbolExtensions/Filtering/SymbolFilterFactory.cs @@ -14,49 +14,58 @@ public static class SymbolFilterFactory /// Creates a composite filter to exclude APIs using the DocIDs provided in the specifed file paths. /// /// A collection of paths where the exclusion files should be searched. + /// An optional custom accessibility symbol filter to use. /// Whether to include internal symbols or not. /// Whether to include effectively private symbols or not. /// Whether to include explicit interface implementation symbols or not. + /// Whether to include implicit symbols or not. /// An instance of the symbol filter. public static ISymbolFilter GetFilterFromFiles(string[]? apiExclusionFilePaths, - bool respectInternals = false, - bool includeEffectivelyPrivateSymbols = true, - bool includeExplicitInterfaceImplementationSymbols = true) + AccessibilitySymbolFilter? accessibilitySymbolFilter = null, + bool respectInternals = false, + bool includeEffectivelyPrivateSymbols = true, + bool includeExplicitInterfaceImplementationSymbols = true, + bool includeImplicitSymbolFilter = true) { DocIdSymbolFilter? docIdSymbolFilter = apiExclusionFilePaths?.Length > 0 ? DocIdSymbolFilter.CreateFromFiles(apiExclusionFilePaths) : null; - return GetCompositeSymbolFilter(docIdSymbolFilter, respectInternals, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols, withImplicitSymbolFilter: true); + return GetCompositeSymbolFilter(docIdSymbolFilter, accessibilitySymbolFilter, respectInternals, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols, includeImplicitSymbolFilter); } /// /// Creates a composite filter to exclude APIs using the DocIDs provided in the specifed list. /// /// A collection of exclusion list. + /// An optional custom accessibility symbol filter to use. /// Whether to include internal symbols or not. /// Whether to include effectively private symbols or not. /// Whether to include explicit interface implementation symbols or not. + /// Whether to include implicit symbols or not. /// An instance of the symbol filter. public static ISymbolFilter GetFilterFromList(string[]? apiExclusionList, - bool respectInternals = false, - bool includeEffectivelyPrivateSymbols = true, - bool includeExplicitInterfaceImplementationSymbols = true) + AccessibilitySymbolFilter? accessibilitySymbolFilter = null, + bool respectInternals = false, + bool includeEffectivelyPrivateSymbols = true, + bool includeExplicitInterfaceImplementationSymbols = true, + bool includeImplicitSymbolFilter = true) { DocIdSymbolFilter? docIdSymbolFilter = apiExclusionList?.Count() > 0 ? DocIdSymbolFilter.CreateFromLists(apiExclusionList) : null; - return GetCompositeSymbolFilter(docIdSymbolFilter, respectInternals, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols, withImplicitSymbolFilter: true); + return GetCompositeSymbolFilter(docIdSymbolFilter, accessibilitySymbolFilter, respectInternals, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols, includeImplicitSymbolFilter); } private static ISymbolFilter GetCompositeSymbolFilter(DocIdSymbolFilter? customFilter, - bool respectInternals, - bool includeEffectivelyPrivateSymbols, - bool includeExplicitInterfaceImplementationSymbols, - bool withImplicitSymbolFilter) + AccessibilitySymbolFilter? accessibilitySymbolFilter, + bool respectInternals, + bool includeEffectivelyPrivateSymbols, + bool includeExplicitInterfaceImplementationSymbols, + bool includeImplicitSymbolFilter) { - AccessibilitySymbolFilter accessibilitySymbolFilter = new( + accessibilitySymbolFilter ??= new( respectInternals, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols); @@ -67,7 +76,7 @@ private static ISymbolFilter GetCompositeSymbolFilter(DocIdSymbolFilter? customF { filter.Add(customFilter); } - if (withImplicitSymbolFilter) + if (includeImplicitSymbolFilter) { filter.Add(new ImplicitSymbolFilter()); } diff --git a/test/Microsoft.DotNet.ApiSymbolExtensions.Tests/SymbolFilterFactoryTests.cs b/test/Microsoft.DotNet.ApiSymbolExtensions.Tests/SymbolFilterFactoryTests.cs index 7c8e78e99827..220d0c2ee436 100644 --- a/test/Microsoft.DotNet.ApiSymbolExtensions.Tests/SymbolFilterFactoryTests.cs +++ b/test/Microsoft.DotNet.ApiSymbolExtensions.Tests/SymbolFilterFactoryTests.cs @@ -15,6 +15,35 @@ public class SymbolFilterFactoryTests [InlineData(true)] [InlineData(false)] public void Test_FilterFromFiles(bool includeCustomType) + { + Test_FilterFromFiles_Internal(includeCustomType, accessibilitySymbolFilter: null); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Test_FilterFromFiles_CustomAccessibilityFilter(bool includeCustomType) + { + Test_FilterFromFiles_Internal(includeCustomType, new AccessibilitySymbolFilter(includeInternalSymbols: true)); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Test_FilterFromList(bool includeCustomType) + { + Test_FilterFromList_Internal(includeCustomType, accessibilitySymbolFilter: null); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void Test_FilterFromList_WithCustomAccessibilityFilter(bool includeCustomType) + { + Test_FilterFromList_Internal(includeCustomType, new AccessibilitySymbolFilter(includeInternalSymbols: true)); + } + + private void Test_FilterFromFiles_Internal(bool includeCustomType, AccessibilitySymbolFilter accessibilitySymbolFilter) { using TempDirectory root = new(); string filePath = Path.Combine(root.DirPath, "exclusions.txt"); @@ -31,6 +60,7 @@ public void Test_FilterFromFiles(bool includeCustomType) CompositeSymbolFilter filter = SymbolFilterFactory.GetFilterFromFiles( apiExclusionFilePaths: [filePath], + accessibilitySymbolFilter: accessibilitySymbolFilter, respectInternals: true, includeEffectivelyPrivateSymbols: true, includeExplicitInterfaceImplementationSymbols: true) as CompositeSymbolFilter; @@ -38,10 +68,7 @@ public void Test_FilterFromFiles(bool includeCustomType) Test_GetFilter_Internal(filter, includeCustomType); } - [Theory] - [InlineData(true)] - [InlineData(false)] - public void Test_FilterFromList(bool includeCustomType) + private void Test_FilterFromList_Internal(bool includeCustomType, AccessibilitySymbolFilter accessibilitySymbolFilter) { List exclusions = ["T:System.Int32", "T:System.String"]; if (!includeCustomType) @@ -51,6 +78,7 @@ public void Test_FilterFromList(bool includeCustomType) CompositeSymbolFilter filter = SymbolFilterFactory.GetFilterFromList( apiExclusionList: exclusions.ToArray(), + accessibilitySymbolFilter: accessibilitySymbolFilter, respectInternals: true, includeEffectivelyPrivateSymbols: true, includeExplicitInterfaceImplementationSymbols: true) as CompositeSymbolFilter; @@ -58,19 +86,19 @@ public void Test_FilterFromList(bool includeCustomType) Test_GetFilter_Internal(filter, includeCustomType); } - private void Test_GetFilter_Internal(CompositeSymbolFilter filter, bool includeCustomType) + private void Test_GetFilter_Internal(CompositeSymbolFilter compositeFilter, bool includeCustomType) { - Assert.NotNull(filter); + Assert.NotNull(compositeFilter); - Assert.Equal(3, filter.Filters.Count); + Assert.Equal(3, compositeFilter.Filters.Count); - DocIdSymbolFilter docIdFilter = filter.Filters[0] as DocIdSymbolFilter; + DocIdSymbolFilter docIdFilter = compositeFilter.Filters[0] as DocIdSymbolFilter; Assert.NotNull(docIdFilter); - ImplicitSymbolFilter implicitFilter = filter.Filters[1] as ImplicitSymbolFilter; + ImplicitSymbolFilter implicitFilter = compositeFilter.Filters[1] as ImplicitSymbolFilter; Assert.NotNull(implicitFilter); - AccessibilitySymbolFilter accessibilityFilter = filter.Filters[2] as AccessibilitySymbolFilter; + AccessibilitySymbolFilter accessibilityFilter = compositeFilter.Filters[2] as AccessibilitySymbolFilter; Assert.NotNull(accessibilityFilter); IAssemblySymbol assemblySymbol = SymbolFactory.GetAssemblyFromSyntax(@" From 648df8ac5dc7357c1219cf028ec56b35ccf585b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?= <1175054+carlossanlop@users.noreply.github.com> Date: Tue, 28 Jan 2025 13:06:25 -0800 Subject: [PATCH 12/12] Fix build failure in GenAPI test using SymbolFilterFactory --- .../CSharpFileBuilderTests.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs b/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs index 6c8fd9af98de..30599082426b 100644 --- a/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs +++ b/test/Microsoft.DotNet.GenAPI.Tests/CSharpFileBuilderTests.cs @@ -41,8 +41,17 @@ private void RunTest(string original, IAssemblySymbolWriter csharpFileBuilder = new CSharpFileBuilder( log.Object, - SymbolFilterFactory.GetFilterFromList([], includeInternalSymbols, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols), - SymbolFilterFactory.GetFilterFromList(excludedAttributeList ?? [], includeInternalSymbols, includeEffectivelyPrivateSymbols, includeExplicitInterfaceImplementationSymbols), + SymbolFilterFactory.GetFilterFromList( + apiExclusionList: [], + accessibilitySymbolFilter: null, + includeInternalSymbols, + includeEffectivelyPrivateSymbols, + includeExplicitInterfaceImplementationSymbols), + SymbolFilterFactory.GetFilterFromList( + apiExclusionList: excludedAttributeList ?? [], accessibilitySymbolFilter: null, + includeInternalSymbols, + includeEffectivelyPrivateSymbols, + includeExplicitInterfaceImplementationSymbols), stringWriter, null, false,