-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix crash when compiling internal attribute constructor #42192
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -661,10 +661,13 @@ internal virtual bool IsMetadataSealed | |
{ | ||
CheckDefinitionInvariant(); | ||
|
||
// All constructors in attributes should be emitted | ||
bool isAttribute = DeclaringCompilation.IsAttributeType(this); | ||
|
||
foreach (var method in this.GetMethodsToEmit()) | ||
{ | ||
Debug.Assert((object)method != null); | ||
if (method.ShouldInclude(context)) | ||
if ((isAttribute && method.MethodKind == MethodKind.Constructor) || method.ShouldInclude(context)) | ||
{ | ||
yield return method; | ||
} | ||
|
@@ -676,7 +679,7 @@ internal virtual bool IsMetadataSealed | |
{ | ||
foreach (var m in generated) | ||
{ | ||
if (m.ShouldInclude(context)) | ||
if ((isAttribute && m.IsConstructor) || m.ShouldInclude(context)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Can we use the same way to perform the constructor check here and above? #Closed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Surprisingly, no - in the "normal" (not generated) method case, |
||
{ | ||
yield return m; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -510,6 +510,76 @@ public event System.Action PrivateRemover { add { } private remove { } } | |
); | ||
} | ||
|
||
[Fact] | ||
[WorkItem(38444, "https://github.com/dotnet/roslyn/issues/38444")] | ||
public void EmitRefAssembly_InternalAttributeConstructor() | ||
{ | ||
CSharpCompilation comp = CreateCompilation(@" | ||
using System; | ||
internal class SomeAttribute : Attribute | ||
{ | ||
internal SomeAttribute() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Please add a regular internal method and verify that it is not emitted. #Closed |
||
{ | ||
} | ||
} | ||
[Some] | ||
public class C | ||
{ | ||
} | ||
"); | ||
|
||
using (var output = new MemoryStream()) | ||
using (var metadataOutput = new MemoryStream()) | ||
{ | ||
EmitResult emitResult = comp.Emit(output, metadataPEStream: metadataOutput, | ||
options: new EmitOptions(includePrivateMembers: false)); | ||
emitResult.Diagnostics.Verify(); | ||
Assert.True(emitResult.Success); | ||
|
||
VerifyMethods(output, "C", new[] { "C..ctor()" }); | ||
VerifyMethods(metadataOutput, "C", new[] { "C..ctor()" }); | ||
VerifyMethods(output, "SomeAttribute", new[] { "SomeAttribute..ctor()" }); | ||
VerifyMethods(metadataOutput, "SomeAttribute", new[] { "SomeAttribute..ctor()" }); | ||
} | ||
} | ||
|
||
[Fact] | ||
[WorkItem(38444, "https://github.com/dotnet/roslyn/issues/38444")] | ||
public void EmitRefAssembly_InternalAttributeConstructor_DoesntIncludeMethods() | ||
{ | ||
CSharpCompilation comp = CreateCompilation(@" | ||
using System; | ||
internal class SomeAttribute : Attribute | ||
{ | ||
internal SomeAttribute() | ||
{ | ||
} | ||
|
||
internal void F() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Please also add a test with a static constructor. #Closed |
||
{ | ||
} | ||
} | ||
[Some] | ||
public class C | ||
{ | ||
} | ||
"); | ||
|
||
using (var output = new MemoryStream()) | ||
using (var metadataOutput = new MemoryStream()) | ||
{ | ||
EmitResult emitResult = comp.Emit(output, metadataPEStream: metadataOutput, | ||
options: new EmitOptions(includePrivateMembers: false)); | ||
emitResult.Diagnostics.Verify(); | ||
Assert.True(emitResult.Success); | ||
|
||
VerifyMethods(output, "C", new[] { "C..ctor()" }); | ||
VerifyMethods(metadataOutput, "C", new[] { "C..ctor()" }); | ||
VerifyMethods(output, "SomeAttribute", new[] { "SomeAttribute..ctor()", "void SomeAttribute.F()" }); | ||
VerifyMethods(metadataOutput, "SomeAttribute", new[] { "SomeAttribute..ctor()" }); | ||
} | ||
} | ||
|
||
private static void VerifyMethods(MemoryStream stream, string containingType, string[] expectedMethods) | ||
{ | ||
stream.Position = 0; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably should avoid calculating this when nothing is going to be filtered out anyway. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the best code pattern to do something like this? I feel like
Lazy
with a lambda is too heavyweight, and abool hasComputedIsAttribute; bool isAttribute;
is kind of gross (so I want confirmation before doing that). (Or did you mean something else by that? Not computing ifcontext.IncludePrivateMembers
is true or something like that?)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, something like that. Do not calculate if
ShouldInclude
doesn't filter anything out.In reply to: 388878100 [](ancestors = 388878100)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also rename the local to something like
alwaysIncludeConstructors
it will cause less confusion once its value is conditionally calculated. The type doesn't stop to be an attribute no matter whatShouldInclude
does.In reply to: 389016262 [](ancestors = 389016262,388878100)