-
Notifications
You must be signed in to change notification settings - Fork 127
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
Add UnconditionalSuppressMessageAttribute #1185
Add UnconditionalSuppressMessageAttribute #1185
Conversation
Co-authored-by: Marek Safar <[email protected]>
…SuppressMessageAttribute's copy.
src/linker/Linker/MessageOrigin.cs
Outdated
@@ -39,6 +51,15 @@ public MessageOrigin (string fileName, int sourceLine = 0, int sourceColumn = 0) | |||
return null; | |||
} | |||
|
|||
internal static MessageOrigin? TryGetOrigin (IMemberDefinition sourceMethod, int ilOffset, |
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 don't think this is the right place. We want the developer to be able to suppress any warning message (e.g. from 3rd party custom step). I think the whole logic should be close to MessageContainer.CreateWarning which probably will need to be expanded with additional "context" state parameter
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.
Absolutely agree.
The suppression should work without any special code from the place where we create the warning - with the sole exception that we require the "context" parameter. I would even go as far as make some strict rule that the context must be specified unless the code is somehow special (like internal errors, command line parsing errors and so on) - otherwise we should always be able to tell what the warning applies to (assembly or more specific).
I think from the API perspective this change should add the "context" attribute to the CreateWarning
method (and maybe also CreateError
for consistency). Then we should have another API which is something like IsSuppressed
- I would probably put it onto the MessageContainer
if it's possible, or if that doesn't work then the LinkContext
. It should take the necessary parameters to decide if a warning will be suppressed or not. Notable it should not require the full warning message - the indented usage would be to avoid computing potentially expensive warning message if we know it's going to be suppressed.
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've moved this logic out of MessageOrigin
by adding the mentioned IsSuppressed
API into the LinkContext
, which is called from within CreateWarningMessage
. It's now mandatory to specify a MessageOrigin
for all created warnings, which must be either a filename or an objetct of a class implementing IMetadataTokenProvider
(modules, types and members). The way to create warnings feels a little bit cumbersome though (Context.LogMessage (MessageContainer.CreateWarningMessage (Context, Message, Code, MessageOrigin, [optional] Subcategory))
), I think this could be enhanced by adding new methods (LogMessage
for info/diags, LogError
for errors, LogWarning
for warnings) and stop passing around the LinkContext
.
src/linker/Linker.Steps/MarkStep.cs
Outdated
@@ -1426,6 +1428,8 @@ bool MarkSpecialCustomAttributeDependencies (CustomAttribute ca, ICustomAttribut | |||
l.Parameters.Count == 1 && l.Parameters[0].ParameterType.IsTypeOf ("System", "Type"), | |||
provider); | |||
return true; | |||
} else if (dt.Name == "UnconditionalSuppressMessageAttribute" && dt.Namespace == "System.Diagnostics.CodeAnalysis") { | |||
_context.Suppressions.AddLocalSuppression (ca, provider.MetadataToken); |
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.
Does it really have to be MetadataToken when the attribute cannot be attached to tokens?
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.
All local suppressions can be attached to a a specific md token. For suppressions which cannot be attached to tokens we'll probably be storing a string instead, but I think this case only applies for suppressions that use the target/scope argument. Support for this will be incorporated in a future PR, since the signature parser will be needed for some scenarios (global suppressions made by specifying target/scope).
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.
ok but to do the decoding here is too late as the suppression on metadata tokens would work for steps starting from MarkStep only
…ionalSuppressMessage
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker.Steps/MarkStep.cs
Outdated
@@ -1426,6 +1428,8 @@ bool MarkSpecialCustomAttributeDependencies (CustomAttribute ca, ICustomAttribut | |||
l.Parameters.Count == 1 && l.Parameters[0].ParameterType.IsTypeOf ("System", "Type"), | |||
provider); | |||
return true; | |||
} else if (dt.Name == "UnconditionalSuppressMessageAttribute" && dt.Namespace == "System.Diagnostics.CodeAnalysis") { | |||
_context.Suppressions.AddLocalSuppression (ca, provider.MetadataToken); |
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.
ok but to do the decoding here is too late as the suppression on metadata tokens would work for steps starting from MarkStep only
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
public class UnconditionalSuppressMessageAttributeState | ||
{ | ||
private readonly AssemblyDefinition _assembly; | ||
private GlobalSuppressions _lazyGlobalSuppressions; |
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.
Why have a class with single field?
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're just making a clear distinction between the global suppressions and the local ones with this class, just as it's done in Roslyn. We could of course have it all in one class but I don't see a reason to not have this.
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 think it'd be more readable to have private readonly Dictionary<MetadataToken, Dictionary<string, SuppressMessageInfo>> _globalSuppressions;
here and hidden inside nested class
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Vitek Karas <[email protected]>
I've removed all things related to global suppressions from this PR. I'll work on them and put them on a following PR to keep this one short and don't delay much in merging the basic support for the |
Enable nullable ref types
src/linker/Linker.Steps/MarkStep.cs
Outdated
@@ -1012,6 +1015,8 @@ protected void MarkAssembly (AssemblyDefinition assembly) | |||
|
|||
foreach (ModuleDefinition module in assembly.Modules) | |||
LazyMarkCustomAttributes (module, module); | |||
|
|||
_context.Suppressions = new UnconditionalSuppressMessageAttributeState (assembly); |
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.
This is probably not right. The _context
is global - for all assemblies, and here we're assigning a state which is for one assembly only. Also - what if there already is another state in that variable? MarkStep doesn't work one assembly at a time - it jumps randomly between assemblies.
We either need to store the suppressions per-assembly or have some kind of global storage keyed of the metadata token providers.
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
test/Mono.Linker.Tests.Cases/WarningSuppression/WarningMessageSuppression.cs
Outdated
Show resolved
Hide resolved
Co-authored-by: Vitek Karas <[email protected]>
This changes the behavior of AddLocalSuppression to add or update a (provider, id) tuple with the last seen suppression instead of keeping the first one seen.
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
!Regex.IsMatch (warningId, "^IL\\d{4}")) { | ||
warningId.Length < 6 || | ||
!warningId.StartsWith ("IL") || | ||
!int.TryParse (warningId.Substring (2, 4), out info.Id)) { |
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.
This means that "IL1234HiThere" will be read as 1234. Probably not what we want. Just check that Length != 6.
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.
SuppressMessageAttribute
allows the user to write anything after a colon, mainly for documentation purposes (e.g., "IL1234:Suppress this"
). I think we should keep this capability.
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
src/linker/Linker/UnconditionalSuppressMessageAttributeState.cs
Outdated
Show resolved
Hide resolved
Check for null before calling `ToLower` on `Scope` parameter Use IMemberDefinition instead of IMdToken for specifying the MessageOrigin
Co-authored-by: Marek Safar <[email protected]> Co-authored-by: Vitek Karas <[email protected]> Commit migrated from dotnet/linker@d51be36
Related to #1147. This PR contains the first effort to support the
UnconditionalSuppressMessageAttribute
. It adds the ability to suppress a specific warning in members and types. Tests were added to show its usage.