Skip to content

Commit c0f2dc7

Browse files
authored
Ensure GenAPI doesn't emit reserved attributes (#33888)
1 parent 7bcdd5a commit c0f2dc7

File tree

5 files changed

+82
-56
lines changed

5 files changed

+82
-56
lines changed

src/GenAPI/Microsoft.DotNet.GenAPI/AttributeDataExtensions.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Linq;
67
using System.Reflection;
78
using Microsoft.CodeAnalysis;
@@ -35,5 +36,37 @@ public static bool IsObsoleteWithUsageTreatedAsCompilationError(this AttributeDa
3536

3637
public static bool IsDefaultMemberAttribute(this AttributeData attribute) =>
3738
attribute.AttributeClass?.ToDisplayString() == typeof(DefaultMemberAttribute).FullName;
39+
40+
private static readonly HashSet<string> _reservedTypes = new(StringComparer.Ordinal)
41+
{
42+
"DynamicAttribute",
43+
"IsReadOnlyAttribute",
44+
"IsUnmanagedAttribute",
45+
"IsByRefLikeAttribute",
46+
"TupleElementNamesAttribute",
47+
"NullableAttribute",
48+
"NullableContextAttribute",
49+
"NullablePublicOnlyAttribute",
50+
"NativeIntegerAttribute",
51+
"ExtensionAttribute",
52+
"RequiredMemberAttribute",
53+
"ScopedRefAttribute",
54+
"RefSafetyRulesAttribute"
55+
};
56+
57+
/// <summary>
58+
/// Determines if an attribute is a reserved attribute class -- these are attributes that may
59+
/// only be applied by the compiler and are an error to be applied by the user in source.
60+
/// See https://github.com/dotnet/roslyn/blob/b8f6dd56f1a0860fcd822bc1e70bec56dc1e97ea/src/Compilers/CSharp/Portable/Symbols/Symbol.cs#L1421
61+
/// </summary>
62+
/// <param name="attribute">The attribute to check</param>
63+
/// <returns>True if the attribute type is reserved.</returns>
64+
public static bool IsReserved(this AttributeData attribute)
65+
{
66+
INamedTypeSymbol? attributeClass = attribute.AttributeClass;
67+
68+
return attributeClass != null && _reservedTypes.Contains(attributeClass.Name) &&
69+
attributeClass.ContainingNamespace.ToDisplayString().Equals("System.Runtime.CompilerServices", StringComparison.Ordinal);
70+
}
3871
}
3972
}

src/GenAPI/Microsoft.DotNet.GenAPI/CSharpFileBuilder.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,9 @@ private SyntaxNode GenerateAssemblyAttributes(IAssemblySymbol assembly, SyntaxNo
242242
ImmutableArray<AttributeData> attributes = assembly.GetAttributes().ExcludeNonVisibleOutsideOfAssembly(_symbolFilter);
243243

244244
// Emit assembly attributes from the IAssemblySymbol
245-
List<SyntaxNode> attributeSyntaxNodes = attributes.Select(attribute => _syntaxGenerator.Attribute(attribute)
245+
List<SyntaxNode> attributeSyntaxNodes = attributes
246+
.Where(attribute => !attribute.IsReserved())
247+
.Select(attribute => _syntaxGenerator.Attribute(attribute)
246248
.WithTrailingTrivia(SyntaxFactory.LineFeed))
247249
.ToList();
248250

src/GenAPI/Microsoft.DotNet.GenAPI/SyntaxNodeExtensions.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ public static SyntaxNode AddMemberAttributes(this SyntaxNode node,
2626
{
2727
continue;
2828
}
29-
node = syntaxGenerator.AddAttributes(node, syntaxGenerator.Attribute(attribute));
3029

30+
if (attribute.IsReserved())
31+
{
32+
continue;
33+
}
34+
35+
node = syntaxGenerator.AddAttributes(node, syntaxGenerator.Attribute(attribute));
3136
}
3237
return node;
3338
}

src/Tests/Microsoft.DotNet.ApiSymbolExtensions.Tests/SymbolFactory.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ private static CSharpCompilation CreateCSharpCompilation(string name, bool enabl
127127
private static IEnumerable<MetadataReference> DefaultReferences { get; } = new[]
128128
{
129129
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
130+
MetadataReference.CreateFromFile(typeof(DynamicAttribute).Assembly.Location),
130131
};
131132
}
132133
}

0 commit comments

Comments
 (0)