diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs index 5ccdf07df9f9b..5693da4ee275e 100644 --- a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs +++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs @@ -90,7 +90,8 @@ private static SingleNamespaceOrTypeDeclaration CreateImplicitClass(ICollection< syntaxReference: container, nameLocation: new SourceLocation(container), memberNames: memberNames, - children: ImmutableArray.Empty); + children: ImmutableArray.Empty, + diagnostics: ImmutableArray.Empty); } /// @@ -181,7 +182,8 @@ private SingleNamespaceOrTypeDeclaration CreateScriptClass( syntaxReference: parentReference, nameLocation: new SourceLocation(parentReference), memberNames: memberNames, - children: children); + children: children, + diagnostics: ImmutableArray.Empty); for (int i = fullName.Length - 2; i >= 0; i--) { @@ -279,24 +281,29 @@ private SingleNamespaceOrTypeDeclaration VisitTypeDeclaration(TypeDeclarationSyn declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasBaseDeclarations; } - if (node.ConstraintClauses.Count > 0) + var diagnostics = DiagnosticBag.GetInstance(); + if (node.Arity == 0) { - declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasConstraints; + Symbol.ReportErrorIfHasConstraints(node.ConstraintClauses, diagnostics); } var memberNames = GetNonTypeMemberNames(((Syntax.InternalSyntax.TypeDeclarationSyntax)(node.Green)).Members, ref declFlags); + var modifiers = node.Modifiers.ToDeclarationModifiers( + allowPartial: true, diagnostics: diagnostics); + return new SingleTypeDeclaration( kind: kind, name: node.Identifier.ValueText, - modifiers: node.Modifiers.ToDeclarationModifiers(), + modifiers: modifiers, arity: node.Arity, declFlags: declFlags, syntaxReference: _syntaxTree.GetReference(node), nameLocation: new SourceLocation(node.Identifier), memberNames: memberNames, - children: VisitTypeChildren(node)); + children: VisitTypeChildren(node), + diagnostics: diagnostics.ToReadOnlyAndFree()); } private ImmutableArray VisitTypeChildren(TypeDeclarationSyntax node) @@ -325,23 +332,27 @@ public override SingleNamespaceOrTypeDeclaration VisitDelegateDeclaration(Delega ? SingleTypeDeclaration.TypeDeclarationFlags.HasAnyAttributes : SingleTypeDeclaration.TypeDeclarationFlags.None; - if (node.ConstraintClauses.Count > 0) + var diagnostics = DiagnosticBag.GetInstance(); + if (node.Arity == 0) { - declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasConstraints; + Symbol.ReportErrorIfHasConstraints(node.ConstraintClauses, diagnostics); } declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasAnyNontypeMembers; + var modifiers = node.Modifiers.ToDeclarationModifiers(allowPartial: false, diagnostics: diagnostics); + return new SingleTypeDeclaration( kind: DeclarationKind.Delegate, name: node.Identifier.ValueText, - modifiers: node.Modifiers.ToDeclarationModifiers(), + modifiers: modifiers, declFlags: declFlags, arity: node.Arity, syntaxReference: _syntaxTree.GetReference(node), nameLocation: new SourceLocation(node.Identifier), memberNames: SpecializedCollections.EmptyCollection(), - children: ImmutableArray.Empty); + children: ImmutableArray.Empty, + diagnostics: diagnostics.ToReadOnlyAndFree()); } public override SingleNamespaceOrTypeDeclaration VisitEnumDeclaration(EnumDeclarationSyntax node) @@ -359,16 +370,20 @@ public override SingleNamespaceOrTypeDeclaration VisitEnumDeclaration(EnumDeclar string[] memberNames = GetEnumMemberNames(members, ref declFlags); + var diagnostics = DiagnosticBag.GetInstance(); + var modifiers = node.Modifiers.ToDeclarationModifiers(allowPartial: false, diagnostics: diagnostics); + return new SingleTypeDeclaration( kind: DeclarationKind.Enum, name: node.Identifier.ValueText, arity: 0, - modifiers: node.Modifiers.ToDeclarationModifiers(), + modifiers: modifiers, declFlags: declFlags, syntaxReference: _syntaxTree.GetReference(node), nameLocation: new SourceLocation(node.Identifier), memberNames: memberNames, - children: ImmutableArray.Empty); + children: ImmutableArray.Empty, + diagnostics: diagnostics.ToReadOnlyAndFree()); } private static string[] GetEnumMemberNames(SeparatedSyntaxList members, ref SingleTypeDeclaration.TypeDeclarationFlags declFlags) diff --git a/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs index 0e8226692eb8d..aafd9bd12a576 100644 --- a/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs +++ b/src/Compilers/CSharp/Portable/Declarations/MergedTypeDeclaration.cs @@ -123,22 +123,6 @@ public bool AnyMemberHasAttributes } } - public bool HasConstraints - { - get - { - foreach (var decl in this.Declarations) - { - if (decl.HasConstraints) - { - return true; - } - } - - return false; - } - } - public LexicalSortKey GetLexicalSortKey(CSharpCompilation compilation) { LexicalSortKey sortKey = new LexicalSortKey(Declarations[0].NameLocation, compilation); diff --git a/src/Compilers/CSharp/Portable/Declarations/SingleNamespaceDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/SingleNamespaceDeclaration.cs index 2e1593a55d3f0..46498c6cb12ee 100644 --- a/src/Compilers/CSharp/Portable/Declarations/SingleNamespaceDeclaration.cs +++ b/src/Compilers/CSharp/Portable/Declarations/SingleNamespaceDeclaration.cs @@ -13,7 +13,7 @@ protected SingleNamespaceDeclaration( SyntaxReference syntaxReference, SourceLocation nameLocation, ImmutableArray children) - : base(name, syntaxReference, nameLocation) + : base(name, syntaxReference, nameLocation, diagnostics: ImmutableArray.Empty) { _children = children; } diff --git a/src/Compilers/CSharp/Portable/Declarations/SingleNamespaceOrTypeDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/SingleNamespaceOrTypeDeclaration.cs index d0436ec3cf094..f4de2ef89773f 100644 --- a/src/Compilers/CSharp/Portable/Declarations/SingleNamespaceOrTypeDeclaration.cs +++ b/src/Compilers/CSharp/Portable/Declarations/SingleNamespaceOrTypeDeclaration.cs @@ -9,14 +9,23 @@ internal abstract class SingleNamespaceOrTypeDeclaration : Declaration private readonly SyntaxReference _syntaxReference; private readonly SourceLocation _nameLocation; + /// + /// Any diagnostics reported while converting the Namespace/Type syntax into the Declaration + /// instance. Generally, we determine and store some diagnostics here because we don't want + /// to have to go back to Syntax when we have our NamespaceSymbol or NamedTypeSymbol. + /// + public readonly ImmutableArray Diagnostics; + protected SingleNamespaceOrTypeDeclaration( string name, SyntaxReference syntaxReference, - SourceLocation nameLocation) + SourceLocation nameLocation, + ImmutableArray diagnostics) : base(name) { _syntaxReference = syntaxReference; _nameLocation = nameLocation; + Diagnostics = diagnostics; } public SourceLocation Location @@ -58,4 +67,4 @@ protected override ImmutableArray GetDeclarationChildren() protected abstract ImmutableArray GetNamespaceOrTypeDeclarationChildren(); } -} +} \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs index 4118c895ccaaf..a5f5f6b1ad9bc 100644 --- a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs +++ b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs @@ -26,7 +26,6 @@ internal enum TypeDeclarationFlags : byte HasBaseDeclarations = 1 << 3, AnyMemberHasAttributes = 1 << 4, HasAnyNontypeMembers = 1 << 5, - HasConstraints = 1 << 6, } internal SingleTypeDeclaration( @@ -38,10 +37,9 @@ internal SingleTypeDeclaration( SyntaxReference syntaxReference, SourceLocation nameLocation, ICollection memberNames, - ImmutableArray children) - : base(name, - syntaxReference, - nameLocation) + ImmutableArray children, + ImmutableArray diagnostics) + : base(name, syntaxReference, nameLocation, diagnostics) { Debug.Assert(kind != DeclarationKind.Namespace); @@ -125,8 +123,6 @@ public bool AnyMemberHasAttributes } } - public bool HasConstraints => (_flags & TypeDeclarationFlags.HasConstraints) != 0; - public bool HasAnyNontypeMembers { get diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index d9cb004a11d5c..aa77f7b95c5d9 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -529,7 +529,7 @@ internal enum ErrorCode ERR_PartialMethodInvalidModifier = 750, ERR_PartialMethodOnlyInPartialClass = 751, ERR_PartialMethodCannotHaveOutParameters = 752, - ERR_PartialMethodOnlyMethods = 753, + // ERR_PartialMethodOnlyMethods = 753, Removed as it is subsumed by ERR_PartialMisplaced ERR_PartialMethodNotExplicit = 754, ERR_PartialMethodExtensionDifference = 755, ERR_PartialMethodOnlyOneLatent = 756, diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index c3f845c305e72..a473ce8cf6d7d 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -1181,74 +1181,57 @@ private AttributeArgumentSyntax ParseAttributeArgument() nameEquals, nameColon, this.ParseExpressionCore()); } - [Flags] - private enum SyntaxModifier + private static DeclarationModifiers GetModifier(SyntaxToken token) + => GetModifier(token.Kind, token.ContextualKind); + + internal static DeclarationModifiers GetModifier(SyntaxKind kind, SyntaxKind contextualKind) { - None = 0, - Public = 0x0001, - Internal = 0x0002, - Protected = 0x0004, - Private = 0x0008, - Sealed = 0x0010, - Abstract = 0x0020, - Static = 0x0040, - Virtual = 0x0080, - Extern = 0x0100, - New = 0x0200, - Override = 0x0400, - ReadOnly = 0x0800, - Volatile = 0x1000, - Unsafe = 0x2000, - Partial = 0x4000, - Async = 0x8000, - } - - private const SyntaxModifier AccessModifiers = SyntaxModifier.Public | SyntaxModifier.Internal | SyntaxModifier.Protected | SyntaxModifier.Private; - - private static SyntaxModifier GetModifier(SyntaxToken token) - { - switch (token.Kind) + switch (kind) { case SyntaxKind.PublicKeyword: - return SyntaxModifier.Public; + return DeclarationModifiers.Public; case SyntaxKind.InternalKeyword: - return SyntaxModifier.Internal; + return DeclarationModifiers.Internal; case SyntaxKind.ProtectedKeyword: - return SyntaxModifier.Protected; + return DeclarationModifiers.Protected; case SyntaxKind.PrivateKeyword: - return SyntaxModifier.Private; + return DeclarationModifiers.Private; case SyntaxKind.SealedKeyword: - return SyntaxModifier.Sealed; + return DeclarationModifiers.Sealed; case SyntaxKind.AbstractKeyword: - return SyntaxModifier.Abstract; + return DeclarationModifiers.Abstract; case SyntaxKind.StaticKeyword: - return SyntaxModifier.Static; + return DeclarationModifiers.Static; case SyntaxKind.VirtualKeyword: - return SyntaxModifier.Virtual; + return DeclarationModifiers.Virtual; case SyntaxKind.ExternKeyword: - return SyntaxModifier.Extern; + return DeclarationModifiers.Extern; case SyntaxKind.NewKeyword: - return SyntaxModifier.New; + return DeclarationModifiers.New; case SyntaxKind.OverrideKeyword: - return SyntaxModifier.Override; + return DeclarationModifiers.Override; case SyntaxKind.ReadOnlyKeyword: - return SyntaxModifier.ReadOnly; + return DeclarationModifiers.ReadOnly; case SyntaxKind.VolatileKeyword: - return SyntaxModifier.Volatile; + return DeclarationModifiers.Volatile; case SyntaxKind.UnsafeKeyword: - return SyntaxModifier.Unsafe; + return DeclarationModifiers.Unsafe; + case SyntaxKind.PartialKeyword: + return DeclarationModifiers.Partial; + case SyntaxKind.AsyncKeyword: + return DeclarationModifiers.Async; case SyntaxKind.IdentifierToken: - switch (token.ContextualKind) + switch (contextualKind) { case SyntaxKind.PartialKeyword: - return SyntaxModifier.Partial; + return DeclarationModifiers.Partial; case SyntaxKind.AsyncKeyword: - return SyntaxModifier.Async; + return DeclarationModifiers.Async; } goto default; default: - return SyntaxModifier.None; + return DeclarationModifiers.None; } } @@ -1259,19 +1242,15 @@ private bool IsPossibleModifier() private static bool IsPossibleModifier(SyntaxToken token) { - return GetModifier(token) != SyntaxModifier.None; + return GetModifier(token) != DeclarationModifiers.None; } private void ParseModifiers(SyntaxListBuilder tokens) { - SyntaxModifier mods = 0; - bool seenNoDuplicates = true; - bool seenNoAccessibilityDuplicates = true; - while (true) { var newMod = GetModifier(this.CurrentToken); - if (newMod == SyntaxModifier.None) + if (newMod == DeclarationModifiers.None) { break; } @@ -1279,59 +1258,45 @@ private void ParseModifiers(SyntaxListBuilder tokens) SyntaxToken modTok; switch (newMod) { - case SyntaxModifier.Partial: + case DeclarationModifiers.Partial: + var nextToken = PeekToken(1); + var isPartialType = this.IsPartialType(); + var isPartialMember = this.IsPartialMember(); + if (isPartialType || isPartialMember) { - var nextToken = PeekToken(1); - if (this.IsPartialType()) - { - modTok = ConvertToKeyword(this.EatToken()); - modTok = CheckFeatureAvailability(modTok, MessageID.IDS_FeaturePartialTypes); - } - else if (this.IsPartialMember()) - { - modTok = ConvertToKeyword(this.EatToken()); - modTok = CheckFeatureAvailability(modTok, MessageID.IDS_FeaturePartialMethod); - } - else if (nextToken.Kind == SyntaxKind.NamespaceKeyword) - { - goto default; - } - else if (nextToken.Kind == SyntaxKind.EnumKeyword || nextToken.Kind == SyntaxKind.DelegateKeyword) - { - modTok = ConvertToKeyword(this.EatToken()); - modTok = this.AddError(modTok, ErrorCode.ERR_PartialMisplaced); - } - else if (!IsPossibleStartOfTypeDeclaration(nextToken.Kind) || GetModifier(nextToken) == SyntaxModifier.None) - { - return; - } - else - { - modTok = ConvertToKeyword(this.EatToken()); - modTok = this.AddError(modTok, ErrorCode.ERR_PartialMisplaced); - } - - break; + // Standard legal cases. + modTok = ConvertToKeyword(this.EatToken()); + modTok = CheckFeatureAvailability(modTok, + isPartialType ? MessageID.IDS_FeaturePartialTypes : MessageID.IDS_FeaturePartialMethod); } - case SyntaxModifier.Async: + else if ( + nextToken.Kind == SyntaxKind.EnumKeyword || + nextToken.Kind == SyntaxKind.DelegateKeyword || + nextToken.Kind == SyntaxKind.NamespaceKeyword || + (IsPossibleStartOfTypeDeclaration(nextToken.Kind) && GetModifier(nextToken) != DeclarationModifiers.None)) + { + // Error tolerance cases. Will report an error about these post parsing. + modTok = ConvertToKeyword(this.EatToken()); + } + else { - if (ShouldAsyncBeTreatedAsModifier(parsingStatementNotDeclaration: false)) - { - modTok = ConvertToKeyword(this.EatToken()); - modTok = CheckFeatureAvailability(modTok, MessageID.IDS_FeatureAsync); - break; - } return; } - default: + + break; + case DeclarationModifiers.Async: + if (!ShouldAsyncBeTreatedAsModifier(parsingStatementNotDeclaration: false)) { - modTok = this.EatToken(); - break; + return; } - } - ReportDuplicateModifiers(ref modTok, newMod, mods, ref seenNoDuplicates, ref seenNoAccessibilityDuplicates); - mods |= newMod; + modTok = ConvertToKeyword(this.EatToken()); + modTok = CheckFeatureAvailability(modTok, MessageID.IDS_FeatureAsync); + break; + default: + modTok = this.EatToken(); + break; + } tokens.Add(modTok); } @@ -1460,37 +1425,7 @@ private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration) private static bool IsNonContextualModifier(SyntaxToken nextToken) { - return GetModifier(nextToken) != SyntaxModifier.None && !SyntaxFacts.IsContextualKeyword(nextToken.ContextualKind); - } - - private void ReportDuplicateModifiers(ref SyntaxToken modTok, SyntaxModifier newMod, SyntaxModifier mods, ref bool seenNoDuplicates, ref bool seenNoAccessibilityDuplicates) - { - if ((mods & newMod) != 0) - { - if (seenNoDuplicates) - { - modTok = this.AddError(modTok, ErrorCode.ERR_DuplicateModifier, SyntaxFacts.GetText(modTok.Kind)); - seenNoDuplicates = false; - } - } - else - { - if ((mods & AccessModifiers) != 0 && (newMod & AccessModifiers) != 0) - { - // Can't have two different access modifiers. - // Exception: "internal protected" or "protected internal" is allowed. - if (!(((newMod == SyntaxModifier.Protected) && (mods & SyntaxModifier.Internal) != 0) || - ((newMod == SyntaxModifier.Internal) && (mods & SyntaxModifier.Protected) != 0))) - { - if (seenNoAccessibilityDuplicates) - { - modTok = this.AddError(modTok, ErrorCode.ERR_BadMemberProtection); - } - - seenNoAccessibilityDuplicates = false; - } - } - } + return GetModifier(nextToken) != DeclarationModifiers.None && !SyntaxFacts.IsContextualKeyword(nextToken.ContextualKind); } private bool IsPartialType() @@ -2392,7 +2327,7 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatement(SyntaxKind par // Check for misplaced modifiers. if we see any, then consider this member // terminated and restart parsing. - if (GetModifier(this.CurrentToken) != SyntaxModifier.None && + if (GetModifier(this.CurrentToken) != DeclarationModifiers.None && this.CurrentToken.ContextualKind != SyntaxKind.PartialKeyword && this.CurrentToken.ContextualKind != SyntaxKind.AsyncKeyword && IsComplete(type)) @@ -7033,8 +6968,8 @@ private bool IsPossibleNewExpression() return false; } - SyntaxModifier modifier = GetModifier(nextToken); - if (modifier == SyntaxModifier.Partial) + DeclarationModifiers modifier = GetModifier(nextToken); + if (modifier == DeclarationModifiers.Partial) { if (SyntaxFacts.IsPredefinedType(PeekToken(2).Kind)) { @@ -7048,7 +6983,7 @@ private bool IsPossibleNewExpression() return false; } } - else if (modifier != SyntaxModifier.None) + else if (modifier != DeclarationModifiers.None) { return false; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index b52c98669c88b..6a6697a2f4dca 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -13,7 +13,6 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { internal sealed class LocalFunctionSymbol : MethodSymbol { - private readonly Binder _binder; private readonly LocalFunctionStatementSyntax _syntax; private readonly Symbol _containingSymbol; @@ -40,17 +39,17 @@ public LocalFunctionSymbol( _syntax = syntax; _containingSymbol = containingSymbol; + _declarationDiagnostics = new DiagnosticBag(); + _declarationModifiers = DeclarationModifiers.Private | DeclarationModifiers.Static | - syntax.Modifiers.ToDeclarationModifiers(); + syntax.Modifiers.ToDeclarationModifiers(allowPartial: false, diagnostics: _declarationDiagnostics); ScopeBinder = binder; binder = binder.WithUnsafeRegionIfNecessary(syntax.Modifiers); - _declarationDiagnostics = new DiagnosticBag(); - if (_syntax.TypeParameterList != null) { binder = new WithMethodTypeParametersBinder(this, binder); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs index ead7961308b41..902c450d061e7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs @@ -13,9 +13,10 @@ internal static DeclarationModifiers MakeAndCheckNontypeMemberModifiers( DeclarationModifiers allowedModifiers, Location errorLocation, DiagnosticBag diagnostics, - out bool modifierErrors) + out bool modifierErrors, + bool allowPartial) { - var result = modifiers.ToDeclarationModifiers(); + var result = modifiers.ToDeclarationModifiers(allowPartial, diagnostics); result = CheckModifiers(result, allowedModifiers, errorLocation, diagnostics, out modifierErrors); if ((result & DeclarationModifiers.AccessibilityMask) == 0) @@ -44,7 +45,8 @@ internal static DeclarationModifiers CheckModifiers( switch (oneError) { case DeclarationModifiers.Partial: - diagnostics.Add(ErrorCode.ERR_PartialMethodOnlyMethods, errorLocation); + // Errors about 'partial' are reported in ToDeclarationModifiers. So no need to report + // any issues here. break; default: @@ -154,13 +156,27 @@ private static DeclarationModifiers ToDeclarationModifier(SyntaxKind kind) } } - public static DeclarationModifiers ToDeclarationModifiers(this SyntaxTokenList modifiers) + public static DeclarationModifiers ToDeclarationModifiers( + this SyntaxTokenList modifiers, bool allowPartial, DiagnosticBag diagnostics) { var result = DeclarationModifiers.None; - + bool seenNoDuplicates = true; + bool seenNoAccessibilityDuplicates = true; + foreach (var modifier in modifiers) { DeclarationModifiers one = ToDeclarationModifier(modifier.ContextualKind()); + + if (one == DeclarationModifiers.Partial && !allowPartial) + { + diagnostics.Add(ErrorCode.ERR_PartialMisplaced, modifier.GetLocation()); + } + + ReportDuplicateModifiers( + modifier, one, result, + ref seenNoDuplicates, ref seenNoAccessibilityDuplicates, + diagnostics); + result |= one; } @@ -174,6 +190,45 @@ public static DeclarationModifiers ToDeclarationModifiers(this SyntaxTokenList m return result; } + private static void ReportDuplicateModifiers( + SyntaxToken modifierToken, + DeclarationModifiers modifierKind, + DeclarationModifiers allModifiers, + ref bool seenNoDuplicates, + ref bool seenNoAccessibilityDuplicates, + DiagnosticBag diagnostics) + { + if ((allModifiers & modifierKind) != 0) + { + if (seenNoDuplicates) + { + diagnostics.Add( + ErrorCode.ERR_DuplicateModifier, + modifierToken.GetLocation(), + SyntaxFacts.GetText(modifierToken.Kind())); + seenNoDuplicates = false; + } + } + else + { + if ((allModifiers & DeclarationModifiers.AccessibilityMask) != 0 && (modifierKind & DeclarationModifiers.AccessibilityMask) != 0) + { + // Can't have two different access modifiers. + // Exception: "internal protected" or "protected internal" is allowed. + if (!(((modifierKind == DeclarationModifiers.Protected) && (allModifiers & DeclarationModifiers.Internal) != 0) || + ((modifierKind == DeclarationModifiers.Internal) && (allModifiers & DeclarationModifiers.Protected) != 0))) + { + if (seenNoAccessibilityDuplicates) + { + diagnostics.Add(ErrorCode.ERR_BadMemberProtection, modifierToken.GetLocation()); + } + + seenNoAccessibilityDuplicates = false; + } + } + } + } + internal static CSDiagnosticInfo CheckAccessibility(DeclarationModifiers modifiers) { if (!IsValidAccessibility(modifiers)) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs index 05d81bed261da..a929ee6988679 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbol.cs @@ -177,7 +177,9 @@ private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, MethodKind DeclarationModifiers.Extern | DeclarationModifiers.Unsafe; - var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers(modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); + var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers( + modifiers, defaultAccess, allowedModifiers, location, diagnostics, + out modifierErrors, allowPartial: false); this.CheckUnsafeModifier(mods, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs index ecc10dab6ff6f..3597ba3aa0590 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDestructorSymbol.cs @@ -108,11 +108,14 @@ public override TypeSymbol ReturnType } } - private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, Location location, DiagnosticBag diagnostics, out bool modifierErrors) + private DeclarationModifiers MakeModifiers( + SyntaxTokenList modifiers, Location location, DiagnosticBag diagnostics, out bool modifierErrors) { // Check that the set of modifiers is allowed const DeclarationModifiers allowedModifiers = DeclarationModifiers.Extern | DeclarationModifiers.Unsafe; - var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers(modifiers, DeclarationModifiers.None, allowedModifiers, location, diagnostics, out modifierErrors); + var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers( + modifiers, DeclarationModifiers.None, allowedModifiers, location, diagnostics, + out modifierErrors, allowPartial: false); this.CheckUnsafeModifier(mods, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventFieldSymbol.cs index 7e22fcc56c537..d8be8f45885ad 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventFieldSymbol.cs @@ -18,7 +18,11 @@ internal sealed class SourceEventFieldSymbol : SourceMemberFieldSymbolFromDeclar private readonly SourceEventSymbol _associatedEvent; internal SourceEventFieldSymbol(SourceEventSymbol associatedEvent, VariableDeclaratorSyntax declaratorSyntax, DiagnosticBag discardedDiagnostics) - : base(associatedEvent.containingType, declaratorSyntax, (associatedEvent.Modifiers & (~DeclarationModifiers.AccessibilityMask)) | DeclarationModifiers.Private, modifierErrors: true, diagnostics: discardedDiagnostics) + : base(associatedEvent.containingType, + declaratorSyntax, + (associatedEvent.Modifiers & (~DeclarationModifiers.AccessibilityMask)) | DeclarationModifiers.Private, + modifierErrors: true, + diagnostics: discardedDiagnostics) { _associatedEvent = associatedEvent; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs index 69121106ec6d0..b56714dff5b20 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs @@ -426,7 +426,9 @@ private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, bool expli allowedModifiers |= DeclarationModifiers.Extern; } - var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers(modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); + var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers( + modifiers, defaultAccess, allowedModifiers, location, diagnostics, + out modifierErrors, allowPartial: false); this.CheckUnsafeModifier(mods, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldLikeEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldLikeEventSymbol.cs index c1873c4fafe9b..eb3016c2c7758 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldLikeEventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldLikeEventSymbol.cs @@ -28,7 +28,6 @@ internal SourceFieldLikeEventSymbol(SourceMemberContainerTypeSymbol containingTy { _name = declaratorSyntax.Identifier.ValueText; - var declaratorDiagnostics = DiagnosticBag.GetInstance(); var declarationSyntax = (VariableDeclarationSyntax)declaratorSyntax.Parent; _type = BindEventType(binder, declarationSyntax.Type, declaratorDiagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 0bc0e9a2ea1aa..625eaa50bd6fa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -178,6 +178,11 @@ internal SourceMemberContainerTypeSymbol( TypeKind typeKind = declaration.Kind.ToTypeKind(); var modifiers = MakeModifiers(typeKind, diagnostics); + foreach (var singleDeclaration in declaration.Declarations) + { + diagnostics.AddRange(singleDeclaration.Diagnostics); + } + int access = (int)(modifiers & DeclarationModifiers.AccessibilityMask); if ((access & (access - 1)) != 0) { // more than one access modifier @@ -310,7 +315,8 @@ private DeclarationModifiers MakeAndCheckTypeModifiers( for (var i = 0; i < partCount; i++) { - var mods = declaration.Declarations[i].Modifiers; + var singleTypeDeclaration = declaration.Declarations[i]; + var mods = singleTypeDeclaration.Modifiers; if (partCount > 1 && (mods & DeclarationModifiers.Partial) == 0) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs index 0628f3c447090..e6b567ed098b9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs @@ -143,7 +143,8 @@ internal static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingTyp var errorLocation = new SourceLocation(firstIdentifier); DeclarationModifiers result = ModifierUtils.MakeAndCheckNontypeMemberModifiers( - modifiers, defaultAccess, allowedModifiers, errorLocation, diagnostics, out modifierErrors); + modifiers, defaultAccess, allowedModifiers, errorLocation, diagnostics, + out modifierErrors, allowPartial: false); if ((result & DeclarationModifiers.Abstract) != 0) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index ebc62825a2d84..d15c2616d2fc4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -790,7 +790,9 @@ private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, MethodKind DeclarationModifiers.Async; } - var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers(modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); + var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers( + modifiers, defaultAccess, allowedModifiers, location, diagnostics, + out modifierErrors, allowPartial: true); this.CheckUnsafeModifier(mods, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index f5fbf9c089985..e58be78f5c202 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -84,15 +84,6 @@ internal SourceNamedTypeSymbol(NamespaceOrTypeSymbol containingSymbol, MergedTyp // Nested types are never unified. _lazyIsExplicitDefinitionOfNoPiaLocalType = ThreeState.False; } - - if (declaration.Arity == 0 && declaration.HasConstraints) - { - foreach (var syntaxRef in this.SyntaxReferences) - { - var constraintClauses = GetConstraintClauses((CSharpSyntaxNode)syntaxRef.GetSyntax()); - ReportErrorIfHasConstraints(constraintClauses, diagnostics); - } - } } #region Syntax diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index b8a68d850934e..022b1c2ab6075 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -414,7 +414,9 @@ private DeclarationModifiers MakeModifiers(AccessorDeclarationSyntax syntax, Loc // Check that the set of modifiers is allowed const DeclarationModifiers allowedModifiers = DeclarationModifiers.AccessibilityMask; - var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers(syntax.Modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); + var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers( + syntax.Modifiers, defaultAccess, allowedModifiers, location, diagnostics, + out modifierErrors, allowPartial: false); // For interface, check there are no accessibility modifiers. // (This check is handled outside of MakeAndCheckModifiers diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index e90e59c563a94..de4b7a7f06982 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -747,7 +747,9 @@ private DeclarationModifiers MakeModifiers(SyntaxTokenList modifiers, bool isExp DeclarationModifiers.Extern; } - var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers(modifiers, defaultAccess, allowedModifiers, location, diagnostics, out modifierErrors); + var mods = ModifierUtils.MakeAndCheckNontypeMemberModifiers( + modifiers, defaultAccess, allowedModifiers, location, diagnostics, + out modifierErrors, allowPartial: false); this.CheckUnsafeModifier(mods, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs index 9a6a281e4cd2c..864a103729053 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceUserDefinedOperatorSymbolBase.cs @@ -42,12 +42,8 @@ protected SourceUserDefinedOperatorSymbolBase( bool modifierErrors; var declarationModifiers = ModifierUtils.MakeAndCheckNontypeMemberModifiers( - modifiersSyntax, - defaultAccess, - allowedModifiers, - location, - diagnostics, - out modifierErrors); + modifiersSyntax, defaultAccess, allowedModifiers, location, diagnostics, + out modifierErrors, allowPartial: false); this.CheckUnsafeModifier(declarationModifiers, diagnostics); diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs index b2e483c95a7ad..630307606bf1d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs @@ -13,6 +13,7 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; +using LanguageParser = Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LanguageParser; namespace Microsoft.CodeAnalysis.CSharp { @@ -1095,7 +1096,7 @@ public ImmutableArray ToMinimalDisplayParts( return SymbolDisplay.ToMinimalDisplayParts(this, semanticModel, position, format); } - protected static void ReportErrorIfHasConstraints( + internal static void ReportErrorIfHasConstraints( SyntaxList constraintClauses, DiagnosticBag diagnostics) { if (constraintClauses.Count > 0) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 72d9159540079..e0b3186c9ac18 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -13337,18 +13337,18 @@ partial int this[int index] "; var comp = CreateStandardCompilation(text); comp.VerifyDiagnostics( - // (5,17): error CS0753: Only methods, classes, structs, or interfaces may be partial - // partial int f; - Diagnostic(ErrorCode.ERR_PartialMethodOnlyMethods, "f"), - // (6,20): error CS0753: Only methods, classes, structs, or interfaces may be partial - // partial object P { get { return null; } } - Diagnostic(ErrorCode.ERR_PartialMethodOnlyMethods, "P"), - // (7,17): error CS0753: Only methods, classes, structs, or interfaces may be partial - // partial int this[int index] - Diagnostic(ErrorCode.ERR_PartialMethodOnlyMethods, "this"), - // (5,17): warning CS0169: The field 'C.f' is never used - // partial int f; - Diagnostic(ErrorCode.WRN_UnreferencedField, "f").WithArguments("C.f")); + // (4,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'struct', 'interface', or 'void' + // partial int f; + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(4, 5), + // (5,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'struct', 'interface', or 'void' + // partial object P { get { return null; } } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(5, 5), + // (6,5): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'struct', 'interface', or 'void' + // partial int this[int index] + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(6, 5), + // (4,17): warning CS0169: The field 'C.f' is never used + // partial int f; + Diagnostic(ErrorCode.WRN_UnreferencedField, "f").WithArguments("C.f").WithLocation(4, 17)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/UserDefinedOperatorErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/UserDefinedOperatorErrorTests.cs index b95b3e1c696af..d0f7587f28a7a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/UserDefinedOperatorErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/UserDefinedOperatorErrorTests.cs @@ -196,9 +196,6 @@ partial class C // (12,12): error CS1004: Duplicate 'public' modifier // public public public static int operator & (C c1, C c2) { return 0; } Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public"), - // (4,40): error CS0753: Only methods, classes, structs, or interfaces may be partial - // partial public static int operator + (C c1, C c2) { return 0; } - Diagnostic(ErrorCode.ERR_PartialMethodOnlyMethods, "+"), // (5,34): error CS0106: The modifier 'abstract' is not valid for this item // abstract public int operator - (C c1, C c2) { return 0; } Diagnostic(ErrorCode.ERR_BadMemberFlag, "-").WithArguments("abstract"), diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs index 3fab94e442b9d..e40609b1b2f4f 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs @@ -5242,6 +5242,61 @@ static void Main() { Assert.Equal((int)ErrorCode.ERR_SemicolonExpected, file.Errors()[0].Code); } + [Fact] + public void TestPartialPartial() + { + var text = @" +partial class PartialPartial +{ + int i = 1; + partial partial void PM(); + partial partial void PM() + { + i = 0; + } + static int Main() + { + PartialPartial t = new PartialPartial(); + t.PM(); + return t.i; + } +} +"; + // These errors aren't great. Ideally we can improve things in the future. + CreateCompilationWithMscorlib(text).VerifyDiagnostics( + // (5,13): error CS1525: Invalid expression term 'partial' + // partial partial void PM(); + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "partial").WithArguments("partial").WithLocation(5, 13), + // (5,13): error CS1002: ; expected + // partial partial void PM(); + Diagnostic(ErrorCode.ERR_SemicolonExpected, "partial").WithLocation(5, 13), + // (6,13): error CS1525: Invalid expression term 'partial' + // partial partial void PM() + Diagnostic(ErrorCode.ERR_InvalidExprTerm, "partial").WithArguments("partial").WithLocation(6, 13), + // (6,13): error CS1002: ; expected + // partial partial void PM() + Diagnostic(ErrorCode.ERR_SemicolonExpected, "partial").WithLocation(6, 13), + // (6,13): error CS0102: The type 'PartialPartial' already contains a definition for '' + // partial partial void PM() + Diagnostic(ErrorCode.ERR_DuplicateNameInClass, "").WithArguments("PartialPartial", "").WithLocation(6, 13), + // (5,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial partial void PM(); + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(5, 5), + // (6,5): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial partial void PM() + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(6, 5)); + } + + [Fact] + public void TestPartialEnum() + { + var text = @"partial enum E{}"; + CreateCompilationWithMscorlib45(text).VerifyDiagnostics( + // (1,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'struct', 'interface', or 'void' + // partial enum E{} + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 1)); + } + [WorkItem(539120, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539120")] [Fact] public void TestEscapedConstructor() diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs index 5242e38bb3ec3..3252732024a16 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParserErrorMessageTests.cs @@ -124,7 +124,13 @@ public static int Main() } "; - ParseAndValidate(test, Diagnostic(ErrorCode.ERR_BadMemberProtection, "internal")); + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (4,13): error CS0107: More than one protection modifier + // private internal void f() {} + Diagnostic(ErrorCode.ERR_BadMemberProtection, "internal").WithLocation(4, 13), + // (4,27): error CS0107: More than one protection modifier + // private internal void f() {} + Diagnostic(ErrorCode.ERR_BadMemberProtection, "f").WithLocation(4, 27)); } [Fact, WorkItem(543622, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543622")] @@ -367,7 +373,7 @@ public static int Main () } "; - ParseAndValidate(test, Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial")); + CreateCompilationWithMscorlib(test).VerifyDiagnostics(); } [Fact] @@ -377,39 +383,59 @@ public void CS0267ERR_PartialMisplaced_Enum() partial enum E { } "; - ParseAndValidate(test, Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial")); + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'struct', 'interface', or 'void' + // partial enum E { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1)); } [Fact] - public void CS0267ERR_PartialMisplaced_Delegate() + public void CS0267ERR_PartialMisplaced_Delegate1() { var test = @" partial delegate E { } "; // Extra errors - ParseAndValidate(test, - // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'struct', 'interface', or 'void' - // partial delegate E { } - Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial"), - // (2,20): error CS1001: Identifier expected - // partial delegate E { } - Diagnostic(ErrorCode.ERR_IdentifierExpected, "{"), - // (2,20): error CS1003: Syntax error, '(' expected - // partial delegate E { } - Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("(", "{"), - // (2,20): error CS1026: ) expected - // partial delegate E { } - Diagnostic(ErrorCode.ERR_CloseParenExpected, "{"), - // (2,20): error CS1002: ; expected - // partial delegate E { } - Diagnostic(ErrorCode.ERR_SemicolonExpected, "{"), - // (2,20): error CS1022: Type or namespace definition, or end-of-file expected - // partial delegate E { } - Diagnostic(ErrorCode.ERR_EOFExpected, "{"), - // (2,22): error CS1022: Type or namespace definition, or end-of-file expected - // partial delegate E { } - Diagnostic(ErrorCode.ERR_EOFExpected, "}")); + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (2,20): error CS1001: Identifier expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(2, 20), + // (2,20): error CS1003: Syntax error, '(' expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_SyntaxError, "{").WithArguments("(", "{").WithLocation(2, 20), + // (2,20): error CS1026: ) expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_CloseParenExpected, "{").WithLocation(2, 20), + // (2,20): error CS1002: ; expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "{").WithLocation(2, 20), + // (2,20): error CS1022: Type or namespace definition, or end-of-file expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_EOFExpected, "{").WithLocation(2, 20), + // (2,22): error CS1022: Type or namespace definition, or end-of-file expected + // partial delegate E { } + Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(2, 22), + // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'struct', 'interface', or 'void' + // partial delegate E { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1), + // (2,18): error CS0246: The type or namespace name 'E' could not be found (are you missing a using directive or an assembly reference?) + // partial delegate E { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "E").WithArguments("E").WithLocation(2, 18)); + } + + [Fact] + public void CS0267ERR_PartialMisplaced_Delegate2() + { + var test = @" +partial delegate void E(); +"; + + // Extra errors + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'struct', 'interface', or 'void' + // partial delegate void E(); + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1)); } // TODO: Extra errors @@ -1390,7 +1416,211 @@ public public static int Main() // CS1004, two public keywords } "; - ParseAndValidate(test, Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public")); + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (6,16): error CS1004: Duplicate 'public' modifier + // public public static int Main() // CS1004, two public keywords + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(6, 16), + // (5,13): warning CS0169: The field 'clx.i' is never used + // int i; + Diagnostic(ErrorCode.WRN_UnreferencedField, "i").WithArguments("x.clx.i").WithLocation(5, 13)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier1() + { + var test = @" +class C +{ + public public C() + { + } +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (4,12): error CS1004: Duplicate 'public' modifier + // public public C() + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(4, 12)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier2() + { + var test = @" +class C +{ + public public ~C() + { + } +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (4,12): error CS1004: Duplicate 'public' modifier + // public public ~C() + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(4, 12), + // (4,20): error CS0106: The modifier 'public' is not valid for this item + // public public ~C() + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C").WithArguments("public").WithLocation(4, 20)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier3() + { + var test = @" +class C +{ + public public int x; +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (4,12): error CS1004: Duplicate 'public' modifier + // public public int x; + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(4, 12), + // (4,23): warning CS0649: Field 'C.x' is never assigned to, and will always have its default value 0 + // public public int x; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "x").WithArguments("C.x", "0").WithLocation(4, 23)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier4() + { + var test = @" +class C +{ + public public int P { get; } +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (4,12): error CS1004: Duplicate 'public' modifier + // public public int P { get; } + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(4, 12)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier5() + { + var test = @" +class C +{ + public public static implicit operator int(C c) => 0; +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (4,12): error CS1004: Duplicate 'public' modifier + // public public static implicit operator int(C c) => 0; + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(4, 12)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier6() + { + var test = @" +class C +{ + public public static int operator +(C c1, C c2) => 0; +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (4,12): error CS1004: Duplicate 'public' modifier + // public public static int operator +(C c1, C c2) => 0; + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(4, 12)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier7() + { + var test = @" +class C +{ + public int P { get; private private set; } +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (4,33): error CS1004: Duplicate 'private' modifier + // public int P { get; private private set; } + Diagnostic(ErrorCode.ERR_DuplicateModifier, "private").WithArguments("private").WithLocation(4, 33)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier8() + { + var test = @" +class C +{ + public public int this[int i] => 0; +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (4,12): error CS1004: Duplicate 'public' modifier + // public public int this[int i] => 0; + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(4, 12)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier9() + { + var test = @" +public public class C +{ +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (2,8): error CS1004: Duplicate 'public' modifier + // public public class C + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(2, 8)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier10() + { + var test = @" +public public interface I +{ +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (2,8): error CS1004: Duplicate 'public' modifier + // public public interface I + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(2, 8)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier11() + { + var test = @" +public public enum E +{ +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (2,8): error CS1004: Duplicate 'public' modifier + // public public enum E + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(2, 8)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier12() + { + var test = @" +public public struct S +{ +}"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (2,8): error CS1004: Duplicate 'public' modifier + // public public struct S + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(2, 8)); + } + + [Fact] + public void CS1004ERR_DuplicateModifier13() + { + var test = @" +public public delegate void D();"; + + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (2,8): error CS1004: Duplicate 'public' modifier + // public public delegate void D(); + Diagnostic(ErrorCode.ERR_DuplicateModifier, "public").WithArguments("public").WithLocation(2, 8)); } [Fact] diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/RoundTrippingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/RoundTrippingTests.cs index 5055eea5ad76a..c3e6f585288fd 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/RoundTrippingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/RoundTrippingTests.cs @@ -398,7 +398,7 @@ public partial() public void TestNegBug876575() { var text = @"partial enum E{}"; - ParseAndRoundTripping(text, 1); + ParseAndRoundTripping(text, errorCount: 0); } [Fact] diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs index c885d07c09c8c..00dda25bf45ee 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs @@ -1841,7 +1841,10 @@ public void EnumDeclaration() var test = @" partial enum en {}; "; - ParseAndValidate(test, new ErrorDescription { Code = 267, Line = 2, Column = 1 }); + CreateCompilationWithMscorlib(test).VerifyDiagnostics( + // (2,1): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'struct', 'interface', or 'void' + // partial enum en {}; + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(2, 1)); } [Fact]