-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Honor attributes on fields #36704
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
Honor attributes on fields #36704
Changes from all commits
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 |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| namespace Microsoft.CodeAnalysis.CSharp.Symbols | ||
| { | ||
| /// <summary> | ||
| /// Information decoded from well-known custom attributes applied on a field. | ||
| /// </summary> | ||
| internal sealed class FieldWellKnownAttributeData : CommonFieldWellKnownAttributeData | ||
| { | ||
| private bool _hasAllowNullAttribute; | ||
| public bool HasAllowNullAttribute | ||
| { | ||
| get | ||
| { | ||
| VerifySealed(expected: true); | ||
| return _hasAllowNullAttribute; | ||
| } | ||
| set | ||
| { | ||
| VerifySealed(expected: false); | ||
| _hasAllowNullAttribute = value; | ||
| SetDataStored(); | ||
| } | ||
| } | ||
|
|
||
| private bool _hasDisallowNullAttribute; | ||
| public bool HasDisallowNullAttribute | ||
| { | ||
| get | ||
| { | ||
| VerifySealed(expected: true); | ||
| return _hasDisallowNullAttribute; | ||
| } | ||
| set | ||
| { | ||
| VerifySealed(expected: false); | ||
| _hasDisallowNullAttribute = value; | ||
| SetDataStored(); | ||
| } | ||
| } | ||
|
|
||
| private bool _hasMaybeNullAttribute; | ||
| public bool HasMaybeNullAttribute | ||
| { | ||
| get | ||
| { | ||
| VerifySealed(expected: true); | ||
| return _hasMaybeNullAttribute; | ||
| } | ||
| set | ||
| { | ||
| VerifySealed(expected: false); | ||
| _hasMaybeNullAttribute = value; | ||
| SetDataStored(); | ||
| } | ||
| } | ||
|
|
||
| private bool? _maybeNullWhenAttribute; | ||
| public bool? MaybeNullWhenAttribute | ||
| { | ||
| get | ||
| { | ||
| VerifySealed(expected: true); | ||
| return _maybeNullWhenAttribute; | ||
| } | ||
| set | ||
| { | ||
| VerifySealed(expected: false); | ||
| _maybeNullWhenAttribute = value; | ||
| SetDataStored(); | ||
| } | ||
| } | ||
|
|
||
| private bool _hasNotNullAttribute; | ||
| public bool HasNotNullAttribute | ||
| { | ||
| get | ||
| { | ||
| VerifySealed(expected: true); | ||
| return _hasNotNullAttribute; | ||
| } | ||
| set | ||
| { | ||
| VerifySealed(expected: false); | ||
| _hasNotNullAttribute = value; | ||
| SetDataStored(); | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,49 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE | |
| /// </summary> | ||
| internal sealed class PEFieldSymbol : FieldSymbol | ||
| { | ||
| private struct PackedFlags | ||
| { | ||
| // Layout: | ||
| // |..............................|vvvvv| | ||
| // | ||
| // f = FlowAnalysisAnnotations. 5 bits (4 value bits + 1 completion bit). | ||
|
|
||
| private const int HasDisallowNullAttribute = 0x1 << 0; | ||
| private const int HasAllowNullAttribute = 0x1 << 1; | ||
| private const int HasMaybeNullAttribute = 0x1 << 2; | ||
| private const int HasNotNullAttribute = 0x1 << 3; | ||
|
Contributor
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. Handling individual bits here is not necessary since
Member
Author
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. PEParameterSymbol can store all the possible annotations, but here we only need to store only four, which are not even contiguous (see below). So I think we have to deal with individual bits/flags. [Flags]
internal enum FlowAnalysisAnnotations
{
None = 0,
AllowNull = 1 << 0,
DisallowNull = 1 << 1,
MaybeNullWhenTrue = 1 << 2,
MaybeNullWhenFalse = 1 << 3,
MaybeNull = MaybeNullWhenTrue | MaybeNullWhenFalse,
NotNullWhenTrue = 1 << 4,
NotNullWhenFalse = 1 << 5,
NotNull = NotNullWhenTrue | NotNullWhenFalse,
AssertsTrue = 1 << 6,
AssertsFalse = 1 << 7,
}In reply to: 296767023 [](ancestors = 296767023) |
||
| private const int FlowAnalysisAnnotationsCompletionBit = 0x1 << 4; | ||
|
|
||
| private int _bits; | ||
|
|
||
| public bool SetFlowAnalysisAnnotations(FlowAnalysisAnnotations value) | ||
| { | ||
| Debug.Assert((value & ~(FlowAnalysisAnnotations.DisallowNull | FlowAnalysisAnnotations.AllowNull | FlowAnalysisAnnotations.MaybeNull | FlowAnalysisAnnotations.NotNull)) == 0); | ||
|
|
||
| int bitsToSet = FlowAnalysisAnnotationsCompletionBit; | ||
| if ((value & FlowAnalysisAnnotations.DisallowNull) != 0) bitsToSet |= PackedFlags.HasDisallowNullAttribute; | ||
| if ((value & FlowAnalysisAnnotations.AllowNull) != 0) bitsToSet |= PackedFlags.HasAllowNullAttribute; | ||
| if ((value & FlowAnalysisAnnotations.MaybeNull) != 0) bitsToSet |= PackedFlags.HasMaybeNullAttribute; | ||
| if ((value & FlowAnalysisAnnotations.NotNull) != 0) bitsToSet |= PackedFlags.HasNotNullAttribute; | ||
|
|
||
| return ThreadSafeFlagOperations.Set(ref _bits, bitsToSet); | ||
| } | ||
|
|
||
| public bool TryGetFlowAnalysisAnnotations(out FlowAnalysisAnnotations value) | ||
| { | ||
| int theBits = _bits; // Read this.bits once to ensure the consistency of the value and completion flags. | ||
| value = FlowAnalysisAnnotations.None; | ||
| if ((theBits & PackedFlags.HasDisallowNullAttribute) != 0) value |= FlowAnalysisAnnotations.DisallowNull; | ||
| if ((theBits & PackedFlags.HasAllowNullAttribute) != 0) value |= FlowAnalysisAnnotations.AllowNull; | ||
| if ((theBits & PackedFlags.HasMaybeNullAttribute) != 0) value |= FlowAnalysisAnnotations.MaybeNull; | ||
| if ((theBits & PackedFlags.HasNotNullAttribute) != 0) value |= FlowAnalysisAnnotations.NotNull; | ||
|
|
||
| var result = (theBits & FlowAnalysisAnnotationsCompletionBit) != 0; | ||
| Debug.Assert(value == 0 || result); | ||
| return result; | ||
| } | ||
| } | ||
|
|
||
| private readonly FieldDefinitionHandle _handle; | ||
| private readonly string _name; | ||
| private readonly FieldAttributes _flags; | ||
|
|
@@ -36,6 +79,7 @@ internal sealed class PEFieldSymbol : FieldSymbol | |
| private int _lazyFixedSize; | ||
| private NamedTypeSymbol _lazyFixedImplementationType; | ||
| private PEEventSymbol _associatedEventOpt; | ||
| private PackedFlags _packedFlags; | ||
|
|
||
| internal PEFieldSymbol( | ||
| PEModuleSymbol moduleSymbol, | ||
|
|
@@ -48,6 +92,7 @@ internal PEFieldSymbol( | |
|
|
||
| _handle = fieldDef; | ||
| _containingType = containingType; | ||
| _packedFlags = new PackedFlags(); | ||
|
|
||
| try | ||
| { | ||
|
|
@@ -272,6 +317,30 @@ internal override TypeWithAnnotations GetFieldType(ConsList<FieldSymbol> fieldsB | |
| return _lazyType.Value; | ||
| } | ||
|
|
||
| public override FlowAnalysisAnnotations FlowAnalysisAnnotations | ||
| { | ||
| get | ||
| { | ||
| FlowAnalysisAnnotations value; | ||
| if (!_packedFlags.TryGetFlowAnalysisAnnotations(out value)) | ||
| { | ||
| value = DecodeFlowAnalysisAttributes(_containingType.ContainingPEModule.Module, _handle); | ||
| _packedFlags.SetFlowAnalysisAnnotations(value); | ||
| } | ||
| return value; | ||
| } | ||
| } | ||
|
|
||
| private static FlowAnalysisAnnotations DecodeFlowAnalysisAttributes(PEModule module, FieldDefinitionHandle handle) | ||
| { | ||
| FlowAnalysisAnnotations annotations = FlowAnalysisAnnotations.None; | ||
| if (module.HasAttribute(handle, AttributeDescription.AllowNullAttribute)) annotations |= FlowAnalysisAnnotations.AllowNull; | ||
| if (module.HasAttribute(handle, AttributeDescription.DisallowNullAttribute)) annotations |= FlowAnalysisAnnotations.DisallowNull; | ||
| if (module.HasAttribute(handle, AttributeDescription.MaybeNullAttribute)) annotations |= FlowAnalysisAnnotations.MaybeNull; | ||
| if (module.HasAttribute(handle, AttributeDescription.NotNullAttribute)) annotations |= FlowAnalysisAnnotations.NotNull; | ||
| return annotations; | ||
| } | ||
|
|
||
| public override bool IsFixedSizeBuffer | ||
| { | ||
| get | ||
|
|
||
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 name was pretty confusing for me at first. It doesn't really say anything about nullable or that it's only about the attributes, not
?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 only represents the annotations from user-specified attributes. I agree this name is a bit confusing (we have annotations like
?and flow analysis annotations like[DisallowNull]). I'll think about this for a subsequent PR.Thanks