diff --git a/.nuget/nuget.exe b/.nuget/nuget.exe
new file mode 100644
index 000000000000..ed048fe88924
Binary files /dev/null and b/.nuget/nuget.exe differ
diff --git a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/AttributesToExclude.txt b/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/AttributesToExclude.txt
deleted file mode 100644
index 4b26bf1f6a67..000000000000
--- a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/AttributesToExclude.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-T:System.AttributeUsageAttribute
-T:System.ComponentModel.EditorBrowsableAttribute
-T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute
-T:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute
\ No newline at end of file
diff --git a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Microsoft.DotNet.ApiDiff.Tool.csproj b/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Microsoft.DotNet.ApiDiff.Tool.csproj
index 21c512fd7fcf..3e6be96c8fd6 100644
--- a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Microsoft.DotNet.ApiDiff.Tool.csproj
+++ b/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Microsoft.DotNet.ApiDiff.Tool.csproj
@@ -12,11 +12,7 @@
true
-
-
- PreserveNewest
-
-
+
diff --git a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Program.cs b/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Program.cs
index 0a8f5cbf47e7..9b27106a6c37 100644
--- a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Program.cs
+++ b/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Program.cs
@@ -14,7 +14,6 @@ namespace Microsoft.DotNet.ApiDiff.Tool;
///
public static class Program
{
- private static readonly string AttributesToExcludeDefaultFileName = "AttributesToExclude.txt";
public static async Task Main(string[] args)
{
@@ -87,10 +86,10 @@ public static async Task Main(string[] args)
Option optionFilesWithAttributesToExclude = new("--attributesToExclude", "-eattrs")
{
- Description = $"An optional array of filepaths, each containing a list of attributes to exclude from the diff. Each file should contain one API full name per line. You can either modify the default file '{AttributesToExcludeDefaultFileName}' to add your own attributes, or include additional files using this command line option.",
+ Description = "An optional array of filepaths, each containing a list of attributes to exclude from the diff. Each file should contain one docID per line in the format 'T:Namespace.TypeName'. If not specified, a default set of common attributes will be excluded automatically. Specifying this option replaces the defaults with the attributes listed in the provided files.",
Arity = ArgumentArity.ZeroOrMore,
Required = false,
- DefaultValueFactory = _ => [new FileInfo(AttributesToExcludeDefaultFileName)]
+ DefaultValueFactory = _ => null
};
Option optionFilesWithApisToExclude = new("--apisToExclude", "-eapis")
diff --git a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff/FileOutputDiffGenerator.cs b/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff/FileOutputDiffGenerator.cs
index db26a6154074..a770a1179a8b 100644
--- a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff/FileOutputDiffGenerator.cs
+++ b/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff/FileOutputDiffGenerator.cs
@@ -1,10 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the
+using System.Diagnostics;
using Microsoft.CodeAnalysis;
-using Microsoft.DotNet.ApiSymbolExtensions.Logging;
using Microsoft.DotNet.ApiSymbolExtensions;
-using System.Diagnostics;
+using Microsoft.DotNet.ApiSymbolExtensions.Logging;
namespace Microsoft.DotNet.ApiDiff;
@@ -75,7 +75,7 @@ internal FileOutputDiffGenerator(ILog log,
_afterFriendlyName = afterFriendlyName;
_tableOfContentsTitle = tableOfContentsTitle;
_assembliesToExclude = CollectListsFromFiles(filesWithAssembliesToExclude);
- _attributesToExclude = filesWithAttributesToExclude != null ? CollectListsFromFiles(filesWithAttributesToExclude) : [];
+ _attributesToExclude = CollectAttributesFromFilesOrDefaults(filesWithAttributesToExclude);
_apisToExclude = CollectListsFromFiles(filesWithApisToExclude);
_addPartialModifier = addPartialModifier;
_writeToDisk = writeToDisk;
@@ -191,4 +191,40 @@ private static string[] CollectListsFromFiles(FileInfo[]? filesWithLists)
return [.. list.Order()];
}
+
+ private static string[] CollectAttributesFromFilesOrDefaults(FileInfo[]? filesWithLists)
+ {
+ // If no files are specified, use default attributes
+ if (filesWithLists == null || filesWithLists.Length == 0)
+ {
+ return [
+ "T:System.AttributeUsageAttribute",
+ "T:System.ComponentModel.EditorBrowsableAttribute",
+ "T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute",
+ "T:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute",
+ "T:System.Windows.Markup.ContentWrapperAttribute",
+ "T:System.Windows.TemplatePartAttribute"
+ ];
+ }
+
+ List list = [];
+
+ foreach (FileInfo file in filesWithLists)
+ {
+ // Only read files that exist, skip missing files silently
+ if (file.Exists)
+ {
+ foreach (string line in File.ReadLines(file.FullName))
+ {
+ if (!list.Contains(line))
+ {
+ // Prevent duplicates.
+ list.Add(line);
+ }
+ }
+ }
+ }
+
+ return [.. list.Order()];
+ }
}
diff --git a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff/MemoryOutputDiffGenerator.cs b/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff/MemoryOutputDiffGenerator.cs
index a481547425f5..b2adf9bba949 100644
--- a/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff/MemoryOutputDiffGenerator.cs
+++ b/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff/MemoryOutputDiffGenerator.cs
@@ -71,7 +71,7 @@ internal MemoryOutputDiffGenerator(
_afterAssemblySymbols = new ConcurrentDictionary(afterAssemblySymbols);
_addPartialModifier = addPartialModifier;
_diagnosticOptions = diagnosticOptions ?? DiffGeneratorFactory.DefaultDiagnosticOptions;
- _attributeSymbolFilter = SymbolFilterFactory.GetFilterFromList(attributesToExclude ?? [], includeExplicitInterfaceImplementationSymbols: true);
+ _attributeSymbolFilter = SymbolFilterFactory.GetFilterFromList(GetAttributesToExcludeOrDefaults(attributesToExclude), includeExplicitInterfaceImplementationSymbols: true);
_symbolFilter = SymbolFilterFactory.GetFilterFromList(apisToExclude ?? [], includeExplicitInterfaceImplementationSymbols: true);
_twoSpacesTrivia = SyntaxFactory.TriviaList(SyntaxFactory.Space, SyntaxFactory.Space);
_missingCloseBrace = SyntaxFactory.MissingToken(SyntaxKind.CloseBraceToken);
@@ -760,6 +760,24 @@ private string GetDocId(SyntaxNode node, SemanticModel model)
return sb.Length == 0 ? null : sb.ToString();
}
+ private static string[] GetAttributesToExcludeOrDefaults(string[]? attributesToExclude)
+ {
+ // If no attributes are specified, use default attributes
+ if (attributesToExclude == null)
+ {
+ return [
+ "T:System.AttributeUsageAttribute",
+ "T:System.ComponentModel.EditorBrowsableAttribute",
+ "T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute",
+ "T:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute",
+ "T:System.Windows.Markup.ContentWrapperAttribute",
+ "T:System.Windows.TemplatePartAttribute"
+ ];
+ }
+
+ return attributesToExclude;
+ }
+
private class ChildrenNodesComparer : IComparer>
{
public int Compare(KeyValuePair first, KeyValuePair second)
diff --git a/test/Microsoft.DotNet.ApiDiff.Tests/Diff.Attribute.Tests.cs b/test/Microsoft.DotNet.ApiDiff.Tests/Diff.Attribute.Tests.cs
index a63f89e546f9..9794da4a301f 100644
--- a/test/Microsoft.DotNet.ApiDiff.Tests/Diff.Attribute.Tests.cs
+++ b/test/Microsoft.DotNet.ApiDiff.Tests/Diff.Attribute.Tests.cs
@@ -734,15 +734,16 @@ public class MyClass
[Fact]
public Task SuppressAllDefaultAttributesUsedByTool()
{
- // The attributes that should get hidden in this test must all be part of
- // the AttributesToExclude.txt file that the ApiDiff tool uses by default.
-
- FileInfo file = new FileInfo("AttributesToExclude.txt");
- if (!file.Exists)
- {
- throw new FileNotFoundException($"{file.FullName} file not found.");
- }
- string[] attributesToExclude = File.ReadAllLines(file.FullName);
+ // Test that the default attributes defined in FileOutputDiffGenerator are properly excluded.
+ // These are the same attributes that are excluded when no -eattrs parameter is specified.
+ string[] attributesToExclude = [
+ "T:System.AttributeUsageAttribute",
+ "T:System.ComponentModel.EditorBrowsableAttribute",
+ "T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute",
+ "T:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute",
+ "T:System.Windows.Markup.ContentWrapperAttribute",
+ "T:System.Windows.TemplatePartAttribute"
+ ];
return RunTestAsync(
beforeCode: """
@@ -787,6 +788,56 @@ public class MyClass
attributesToExclude: attributesToExclude);
}
+ [Fact]
+ public Task DefaultBehaviorExcludesDefaultAttributes()
+ {
+ // Test that when no attributesToExclude is specified (null),
+ // the tool automatically excludes the default set of attributes.
+ // This simulates the behavior when -eattrs is not specified on the command line.
+
+ return RunTestAsync(
+ beforeCode: """
+ namespace MyNamespace
+ {
+ public class MyClass
+ {
+ }
+ }
+ """,
+ afterCode: """
+ using System;
+ namespace MyNamespace
+ {
+ [System.AttributeUsage(System.AttributeTargets.All)]
+ public class MyAttributeAttribute : System.Attribute
+ {
+ public MyAttributeAttribute() { }
+ }
+ [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
+ [System.Diagnostics.CodeAnalysis.RequiresDynamicCode("Text")]
+ [MyAttribute]
+ [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode("Text")]
+ public class MyClass
+ {
+ }
+ }
+ """,
+ expectedCode: """
+ namespace MyNamespace
+ {
+ + [MyNamespace.MyAttributeAttribute]
+ public class MyClass
+ {
+ }
+ + public class MyAttributeAttribute : System.Attribute
+ + {
+ + public MyAttributeAttribute();
+ + }
+ }
+ """,
+ attributesToExclude: null); // null simulates default behavior
+ }
+
[Fact]
public Task SuppressNone() => RunTestAsync(
beforeCode: """
diff --git a/test/Microsoft.DotNet.ApiDiff.Tests/Microsoft.DotNet.ApiDiff.Tests.csproj b/test/Microsoft.DotNet.ApiDiff.Tests/Microsoft.DotNet.ApiDiff.Tests.csproj
index 0614262e2f1e..cbbb244af138 100644
--- a/test/Microsoft.DotNet.ApiDiff.Tests/Microsoft.DotNet.ApiDiff.Tests.csproj
+++ b/test/Microsoft.DotNet.ApiDiff.Tests/Microsoft.DotNet.ApiDiff.Tests.csproj
@@ -14,11 +14,6 @@
-
- PreserveNewest
-
diff --git "a/test/TestAssets/TestProjects/ProjectWithEsProjReference/obj\\Debug/\\package.g.props" "b/test/TestAssets/TestProjects/ProjectWithEsProjReference/obj\\Debug/\\package.g.props"
new file mode 100644
index 000000000000..89839c8c46de
--- /dev/null
+++ "b/test/TestAssets/TestProjects/ProjectWithEsProjReference/obj\\Debug/\\package.g.props"
@@ -0,0 +1,12 @@
+
+
+
+ lib
+ 1.0.0
+ A test project to verify .NET SDK compatibility for workload restore and non-Managed projects
+ index.js
+ echo "Error: no test specified" && exit 1
+
+ MIT
+
+
\ No newline at end of file
diff --git a/test/TestAssets/TestProjects/TestWebAppSimple/.BundledAspNetCoreVersion b/test/TestAssets/TestProjects/TestWebAppSimple/.BundledAspNetCoreVersion
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/test/TestAssets/TestProjects/TestWebAppSimple/.DefaultPatchVersionForAspNetCoreApp2_1 b/test/TestAssets/TestProjects/TestWebAppSimple/.DefaultPatchVersionForAspNetCoreApp2_1
new file mode 100644
index 000000000000..e69de29bb2d1