提交 845b3792 编写于 作者: T TomasMatousek

Avoid adding enum members into static initializer list - they are not used.

Assert that Syntax of FieldORPropertyInitializer is never null - which wasn't the case when enum members with implicit values were added. (changeset 1397098)
上级 c1666645
......@@ -97,7 +97,7 @@ internal struct ProcessedFieldInitializers
foreach (FieldOrPropertyInitializer initializer in siblingInitializers)
{
FieldSymbol fieldSymbol = initializer.Field;
FieldSymbol fieldSymbol = initializer.FieldOpt;
Debug.Assert((object)fieldSymbol != null);
// A constant field of type decimal needs a field initializer, so
......@@ -156,7 +156,7 @@ internal struct ProcessedFieldInitializers
for (int j = 0; j < siblingInitializers.Length; j++)
{
var initializer = siblingInitializers[j];
var fieldSymbol = initializer.Field;
var fieldSymbol = initializer.FieldOpt;
if ((object)fieldSymbol != null && fieldSymbol.IsConst)
{
......
......@@ -11,20 +11,21 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
internal struct FieldOrPropertyInitializer
{
/// <summary>
/// The field being initialized (possibly a backing field of a property), or null if this is a global statement.
/// The field being initialized (possibly a backing field of a property), or null if this is a top-level statement in script code.
/// </summary>
internal readonly FieldSymbol Field;
internal readonly FieldSymbol FieldOpt;
/// <summary>
/// A reference to <see cref="EqualsValueClauseSyntax"/> or <see cref="GlobalStatementSyntax"/>.
/// A reference to <see cref="EqualsValueClauseSyntax"/> or top-level <see cref="StatementSyntax"/> in script code.
/// </summary>
internal readonly SyntaxReference Syntax;
public FieldOrPropertyInitializer(FieldSymbol field, SyntaxReference syntax)
public FieldOrPropertyInitializer(FieldSymbol fieldOpt, SyntaxNode syntax)
{
Debug.Assert(((object)field != null) || (syntax != null));
Field = field;
Syntax = syntax;
Debug.Assert(syntax.IsKind(SyntaxKind.EqualsValueClause) && fieldOpt != null || syntax is StatementSyntax);
FieldOpt = fieldOpt;
Syntax = syntax.GetReference();
}
}
}
......@@ -2110,10 +2110,10 @@ private static void AddNestedTypesToDictionary(Dictionary<string, ImmutableArray
private class MembersAndInitializersBuilder
{
public ArrayBuilder<Symbol> NonTypeNonIndexerMembers = ArrayBuilder<Symbol>.GetInstance();
public ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>> StaticInitializers = ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>>.GetInstance();
public ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>> InstanceInitializers = ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>>.GetInstance();
public ArrayBuilder<SyntaxReference> IndexerDeclarations = ArrayBuilder<SyntaxReference>.GetInstance();
public readonly ArrayBuilder<Symbol> NonTypeNonIndexerMembers = ArrayBuilder<Symbol>.GetInstance();
public readonly ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>> StaticInitializers = ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>>.GetInstance();
public readonly ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>> InstanceInitializers = ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>>.GetInstance();
public readonly ArrayBuilder<SyntaxReference> IndexerDeclarations = ArrayBuilder<SyntaxReference>.GetInstance();
public MembersAndInitializers ToReadOnlyAndFree()
{
......@@ -2477,8 +2477,6 @@ private static bool ParametersMatchEventAccessor(EventSymbol eventSymbol, Immuta
private void AddEnumMembers(MembersAndInitializersBuilder result, EnumDeclarationSyntax syntax, DiagnosticBag diagnostics)
{
ArrayBuilder<FieldOrPropertyInitializer> initializers = null;
// The previous enum constant used to calculate subsequent
// implicit enum constants. (This is the most recent explicit
// enum constant or the first implicit constant if no explicit values.)
......@@ -2487,71 +2485,55 @@ private void AddEnumMembers(MembersAndInitializersBuilder result, EnumDeclaratio
// Offset from "otherSymbol".
int otherSymbolOffset = 0;
foreach (var m in syntax.Members)
foreach (var member in syntax.Members)
{
switch (m.Kind())
{
case SyntaxKind.EnumMemberDeclaration:
{
SourceEnumConstantSymbol symbol;
var valueOpt = m.EqualsValue;
if (valueOpt != null)
{
symbol = SourceEnumConstantSymbol.CreateExplicitValuedConstant(this, m, diagnostics);
}
else
{
symbol = SourceEnumConstantSymbol.CreateImplicitValuedConstant(this, m, otherSymbol, otherSymbolOffset, diagnostics);
}
SourceEnumConstantSymbol symbol;
var valueOpt = member.EqualsValue;
result.NonTypeNonIndexerMembers.Add(symbol);
if ((valueOpt != null) || ((object)otherSymbol == null))
{
otherSymbol = symbol;
otherSymbolOffset = 1;
}
else
{
otherSymbolOffset++;
}
if (valueOpt != null)
{
symbol = SourceEnumConstantSymbol.CreateExplicitValuedConstant(this, member, diagnostics);
}
else
{
symbol = SourceEnumConstantSymbol.CreateImplicitValuedConstant(this, member, otherSymbol, otherSymbolOffset, diagnostics);
}
// The symbol is added to the set of initializers, even for
// implicit values since it's necessary to generate constants
// for each member to catch errors such as overflow.
AddInitializer(ref initializers, symbol, valueOpt);
}
break;
result.NonTypeNonIndexerMembers.Add(symbol);
default:
throw ExceptionUtilities.UnexpectedValue(m.Kind());
if (valueOpt != null || (object)otherSymbol == null)
{
otherSymbol = symbol;
otherSymbolOffset = 1;
}
else
{
otherSymbolOffset++;
}
}
AddInitializers(ref result.StaticInitializers, initializers);
}
private static void AddInitializer(ref ArrayBuilder<FieldOrPropertyInitializer> initializers, FieldSymbol field, CSharpSyntaxNode node)
private static void AddInitializer(ref ArrayBuilder<FieldOrPropertyInitializer> initializers, FieldSymbol fieldOpt, CSharpSyntaxNode node)
{
if (initializers == null)
{
initializers = new ArrayBuilder<FieldOrPropertyInitializer>();
}
else
{
// initializers should be added in syntax order:
Debug.Assert(node.SyntaxTree == initializers.Last().Syntax.SyntaxTree);
Debug.Assert(node.SpanStart > initializers.Last().Syntax.GetSyntax().SpanStart);
}
initializers.Add(new FieldOrPropertyInitializer(field, node.GetReferenceOrNull()));
initializers.Add(new FieldOrPropertyInitializer(fieldOpt, node));
}
private static void AddInitializers(ref ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>> allInitializers, ArrayBuilder<FieldOrPropertyInitializer> siblings)
private static void AddInitializers(ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>> allInitializers, ArrayBuilder<FieldOrPropertyInitializer> siblingsOpt)
{
if (siblings != null)
if (siblingsOpt != null)
{
if (allInitializers == null)
{
allInitializers = new ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>>();
}
allInitializers.Add(siblings.ToImmutableAndFree());
allInitializers.Add(siblingsOpt.ToImmutableAndFree());
}
}
......@@ -2647,11 +2629,11 @@ private void CheckForStructBadInitializers(MembersAndInitializersBuilder builder
Debug.Assert(TypeKind == TypeKind.Struct);
foreach (var initializers in builder.InstanceInitializers)
{
{
foreach (FieldOrPropertyInitializer initializer in initializers)
{
// '{0}': cannot have instance field initializers in structs
diagnostics.Add(ErrorCode.ERR_FieldInitializerInStruct, (initializer.Field.AssociatedSymbol ?? initializer.Field).Locations[0], this);
{
// '{0}': cannot have instance field initializers in structs
diagnostics.Add(ErrorCode.ERR_FieldInitializerInStruct, (initializer.FieldOpt.AssociatedSymbol ?? initializer.FieldOpt).Locations[0], this);
}
}
}
......@@ -2677,6 +2659,7 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder<Symbol> members,
hasInstanceConstructor = true;
hasParameterlessInstanceConstructor = hasParameterlessInstanceConstructor || method.ParameterCount == 0;
break;
case MethodKind.StaticConstructor:
hasStaticConstructor = true;
break;
......@@ -2690,27 +2673,11 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder<Symbol> members,
}
}
var hasStaticInitializer = false;
if (staticInitializers != null)
{
foreach (var siblings in staticInitializers)
{
foreach (var initializer in siblings)
{
// constants don't count, since they do not exist as fields at runtime
// NOTE: even for decimal constants (which require field initializers),
// we do not create .cctor here since a static constructor implicitly created for a decimal
// should not appear in the list returned by public API like GetMembers().
if (!initializer.Field.IsConst)
{
hasStaticInitializer = true;
goto OUTER;
}
}
}
}
OUTER:
// constants don't count, since they do not exist as fields at runtime
// NOTE: even for decimal constants (which require field initializers),
// we do not create .cctor here since a static constructor implicitly created for a decimal
// should not appear in the list returned by public API like GetMembers().
var hasStaticInitializer = HasNonConstantInitializer(staticInitializers);
// NOTE: Per section 11.3.8 of the spec, "every struct implicitly has a parameterless instance constructor".
// We won't insert a parameterless constructor for a struct if there already is one.
......@@ -2735,6 +2702,25 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder<Symbol> members,
}
}
private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldOrPropertyInitializer>> initializers)
{
if (initializers != null)
{
foreach (var siblings in initializers)
{
foreach (var initializer in siblings)
{
if (!initializer.FieldOpt.IsConst)
{
return true;
}
}
}
}
return false;
}
private void AddNonTypeMembers(
MembersAndInitializersBuilder result,
SyntaxList<MemberDeclarationSyntax> members,
......@@ -3014,8 +3000,8 @@ private void AddSynthesizedConstructorsIfNecessary(ArrayBuilder<Symbol> members,
}
}
AddInitializers(ref result.InstanceInitializers, instanceInitializers);
AddInitializers(ref result.StaticInitializers, staticInitializers);
AddInitializers(result.InstanceInitializers, instanceInitializers);
AddInitializers(result.StaticInitializers, staticInitializers);
}
private static bool IsGlobalCodeAllowed(CSharpSyntaxNode parent)
......
......@@ -990,7 +990,7 @@ internal override void PostDecodeWellKnownAttributes(ImmutableArray<CSharpAttrib
{
foreach (var singleInitializer in initializerGroup)
{
if (!singleInitializer.Field.IsMetadataConstant)
if (!singleInitializer.FieldOpt.IsMetadataConstant)
{
// CS8028: '{0}': a class with the ComImport attribute cannot specify field initializers.
diagnostics.Add(ErrorCode.ERR_ComImportWithInitializers, singleInitializer.Syntax.GetLocation(), this.Name);
......
......@@ -19,8 +19,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
''' <see cref="EqualsValueSyntax"/>,
''' <see cref="AsNewClauseSyntax"/>,
''' <see cref="ModifiedIdentifierSyntax"/>,
''' <see cref="StatementSyntax"/> (top-level statement), or
''' Nothing (enums field with an implicit value).
''' <see cref="StatementSyntax"/> (top-level statement).
''' </summary>
Public ReadOnly Syntax As SyntaxReference
......@@ -29,7 +28,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
''' </summary>
''' <param name="syntax">The initializer syntax for the statement.</param>
Public Sub New(syntax As SyntaxReference)
Debug.Assert(syntax IsNot Nothing)
Debug.Assert(TypeOf syntax.GetSyntax() Is StatementSyntax)
Me.Syntax = syntax
End Sub
......@@ -40,10 +39,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
''' <param name="syntax">The initializer syntax for the field.</param>
Public Sub New(field As FieldSymbol, syntax As SyntaxReference)
Debug.Assert(field IsNot Nothing)
Debug.Assert(syntax Is Nothing OrElse
syntax.GetVisualBasicSyntax.Kind = SyntaxKind.AsNewClause OrElse
syntax.GetVisualBasicSyntax.Kind = SyntaxKind.EqualsValue OrElse
syntax.GetVisualBasicSyntax.Kind = SyntaxKind.ModifiedIdentifier)
Debug.Assert(syntax.GetSyntax().IsKind(SyntaxKind.AsNewClause) OrElse
syntax.GetSyntax().IsKind(SyntaxKind.EqualsValue) OrElse
syntax.GetSyntax().IsKind(SyntaxKind.ModifiedIdentifier))
Me.FieldsOrProperty = ImmutableArray.Create(Of Symbol)(field)
Me.Syntax = syntax
......@@ -54,7 +52,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
''' </summary>
Public Sub New(fieldsOrProperties As ImmutableArray(Of Symbol), syntax As SyntaxReference)
Debug.Assert(Not fieldsOrProperties.IsEmpty)
Debug.Assert(syntax.GetSyntax.Kind = SyntaxKind.AsNewClause OrElse syntax.GetSyntax.Kind = SyntaxKind.EqualsValue)
Debug.Assert(syntax.GetSyntax().IsKind(SyntaxKind.AsNewClause) OrElse syntax.GetSyntax().IsKind(SyntaxKind.EqualsValue))
Me.FieldsOrProperty = fieldsOrProperties
Me.Syntax = syntax
......@@ -68,7 +66,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Public Sub New([property] As PropertySymbol, syntax As SyntaxReference)
Debug.Assert([property] IsNot Nothing)
Debug.Assert(syntax IsNot Nothing)
Debug.Assert(syntax.GetSyntax.Kind = SyntaxKind.AsNewClause OrElse syntax.GetSyntax.Kind = SyntaxKind.EqualsValue)
Debug.Assert(syntax.GetSyntax().IsKind(SyntaxKind.AsNewClause) OrElse syntax.GetSyntax().IsKind(SyntaxKind.EqualsValue))
Me.FieldsOrProperty = ImmutableArray.Create(Of Symbol)([property])
Me.Syntax = syntax
......
......@@ -1555,13 +1555,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
''' Adds a field initializer for the field to list of field initializers
''' </summary>
''' <param name="initializers">All initializers.</param>
''' <param name="fieldInitializer">The field initializer to add to the list of initializers.</param>
Friend Shared Sub AddInitializer(ByRef initializers As ArrayBuilder(Of FieldOrPropertyInitializer), fieldInitializer As FieldOrPropertyInitializer)
''' <param name="initializer">The field initializer to add to the list of initializers.</param>
Friend Shared Sub AddInitializer(ByRef initializers As ArrayBuilder(Of FieldOrPropertyInitializer), initializer As FieldOrPropertyInitializer)
If initializers Is Nothing Then
initializers = ArrayBuilder(Of FieldOrPropertyInitializer).GetInstance()
Else
' initializers should be added in syntax order
Debug.Assert(initializer.Syntax.SyntaxTree Is initializers.Last().Syntax.SyntaxTree)
Debug.Assert(initializer.Syntax.Span.Start > initializers.Last().Syntax.Span.Start)
End If
initializers.Add(fieldInitializer)
initializers.Add(initializer)
End Sub
''' <summary>
......
......@@ -256,7 +256,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
ElseIf TypeKind = TypeKind.Enum Then
Dim enumBlock = DirectCast(node, EnumBlockSyntax)
AddEnumMembers(enumBlock, binder, diagBag, members, staticInitializers)
AddEnumMembers(enumBlock, binder, diagBag, members)
Else
Dim typeBlock = DirectCast(node, TypeBlockSyntax)
For Each memberSyntax In typeBlock.Members
......@@ -682,10 +682,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Sub
Private Sub AddEnumMembers(syntax As EnumBlockSyntax,
bodyBinder As Binder,
diagnostics As DiagnosticBag,
members As MembersAndInitializersBuilder,
ByRef staticInitializers As ArrayBuilder(Of FieldOrPropertyInitializer))
bodyBinder As Binder,
diagnostics As DiagnosticBag,
members As MembersAndInitializersBuilder)
Dim valField = New SynthesizedFieldSymbol(
Me,
......@@ -705,43 +704,35 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
' Offset from "otherSymbol".
Dim otherSymbolOffset As Integer = 0
Dim memberList = syntax.Members
If memberList.Count = 0 Then
If syntax.Members.Count = 0 Then
Binder.ReportDiagnostic(diagnostics, syntax.EnumStatement.Identifier, ERRID.ERR_BadEmptyEnum1, syntax.EnumStatement.Identifier.ValueText)
Else
For Each member In syntax.Members
If member.Kind <> SyntaxKind.EnumMemberDeclaration Then
' skip invalid syntax
Continue For
End If
Dim declaration = DirectCast(member, EnumMemberDeclarationSyntax)
Dim symbol As SourceEnumConstantSymbol
Dim valueOpt = declaration.Initializer
If valueOpt IsNot Nothing Then
symbol = SourceEnumConstantSymbol.CreateExplicitValuedConstant(Me, bodyBinder, declaration, diagnostics)
Else
symbol = SourceEnumConstantSymbol.CreateImplicitValuedConstant(Me, bodyBinder, declaration, otherSymbol, otherSymbolOffset, diagnostics)
End If
Return
End If
If (valueOpt IsNot Nothing) OrElse (otherSymbol Is Nothing) Then
otherSymbol = symbol
otherSymbolOffset = 1
Else
otherSymbolOffset = otherSymbolOffset + 1
End If
For Each member In syntax.Members
If member.Kind <> SyntaxKind.EnumMemberDeclaration Then
' skip invalid syntax
Continue For
End If
AddMember(symbol, bodyBinder, members, omitDiagnostics:=False)
Dim declaration = DirectCast(member, EnumMemberDeclarationSyntax)
Dim symbol As SourceEnumConstantSymbol
Dim valueOpt = declaration.Initializer
If valueOpt IsNot Nothing Then
symbol = SourceEnumConstantSymbol.CreateExplicitValuedConstant(Me, bodyBinder, declaration, diagnostics)
Else
symbol = SourceEnumConstantSymbol.CreateImplicitValuedConstant(Me, bodyBinder, declaration, otherSymbol, otherSymbolOffset, diagnostics)
End If
Dim initializer = New FieldOrPropertyInitializer(symbol, If(valueOpt IsNot Nothing, bodyBinder.GetSyntaxReference(valueOpt), Nothing))
If (valueOpt IsNot Nothing) OrElse (otherSymbol Is Nothing) Then
otherSymbol = symbol
otherSymbolOffset = 1
Else
otherSymbolOffset = otherSymbolOffset + 1
End If
' The symbol is added to the set of initializers, even for
' implicit values since it's necessary to generate constants
' for each member to catch errors such as overflow.
SourceNamedTypeSymbol.AddInitializer(staticInitializers, initializer)
Next
End If
AddMember(symbol, bodyBinder, members, omitDiagnostics:=False)
Next
End Sub
#End Region
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册