提交 1d6a245d 编写于 作者: V vsadov

Parsing support for readonly ref returns.

* Syntax model and Parsing
* Support for 7.1 language version - just enough to unblock testing.
上级 8d712fa6
......@@ -750,6 +750,7 @@
<Compile Include="Syntax\DestructorDeclarationSyntax.cs" />
<Compile Include="Syntax\DirectiveTriviaSyntax.cs" />
<Compile Include="Syntax\ExpressionStatementSyntax.cs" />
<Compile Include="Syntax\RefTypeSyntax.cs" />
<Compile Include="Syntax\GenericNameSyntax.cs" />
<Compile Include="Syntax\CSharpSyntaxTree.DebuggerSyntaxTree.cs" />
<Compile Include="Syntax\IdentifierNameSyntax.cs" />
......
......@@ -10133,6 +10133,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to readonly references.
/// </summary>
internal static string IDS_FeatureReadonlyReferences {
get {
return ResourceManager.GetString("IDS_FeatureReadonlyReferences", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to byref locals and returns.
/// </summary>
......
......@@ -4197,6 +4197,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="IDS_FeatureRefLocalsReturns" xml:space="preserve">
<value>byref locals and returns</value>
</data>
<data name="IDS_FeatureReadonlyReferences" xml:space="preserve">
<value>readonly references</value>
</data>
<data name="CompilationC" xml:space="preserve">
<value>Compilation (C#): </value>
</data>
......
......@@ -127,6 +127,9 @@ internal enum MessageID
IDS_FeatureExpressionBodiedAccessor = MessageBase + 12715,
IDS_FeatureExpressionBodiedDeOrConstructor = MessageBase + 12716,
IDS_ThrowExpression = MessageBase + 12717,
IDS_FeatureReadonlyReferences = MessageBase + 12718,
}
// Message IDs may refer to strings that need to be localized.
......@@ -183,6 +186,10 @@ internal static LanguageVersion RequiredVersion(this MessageID feature)
// Checks are in the LanguageParser unless otherwise noted.
switch (feature)
{
// C# 7.1 features.
case MessageID.IDS_FeatureReadonlyReferences:
return LanguageVersion.CSharp7_1;
// C# 7 features.
case MessageID.IDS_FeatureBinaryLiteral:
case MessageID.IDS_FeatureDigitSeparator:
......
......@@ -68,6 +68,11 @@ public enum LanguageVersion
/// </summary>
CSharp7 = 7,
/// <summary>
/// C# language version 7.1
/// </summary>
CSharp7_1 = 71,
/// <summary>
/// The latest version of the language supported.
/// </summary>
......@@ -81,6 +86,7 @@ internal static LanguageVersion MapSpecifiedToEffectiveVersion(this LanguageVers
switch (version)
{
case LanguageVersion.Latest:
return LanguageVersion.CSharp7_1;
case LanguageVersion.Default:
return LanguageVersion.CSharp7;
default:
......@@ -90,7 +96,20 @@ internal static LanguageVersion MapSpecifiedToEffectiveVersion(this LanguageVers
internal static bool IsValid(this LanguageVersion value)
{
return value >= LanguageVersion.CSharp1 && value <= LanguageVersion.CSharp7;
switch (value)
{
case LanguageVersion.CSharp1:
case LanguageVersion.CSharp2:
case LanguageVersion.CSharp3:
case LanguageVersion.CSharp4:
case LanguageVersion.CSharp5:
case LanguageVersion.CSharp6:
case LanguageVersion.CSharp7:
case LanguageVersion.CSharp7_1:
return true;
}
return false;
}
internal static object Localize(this LanguageVersion value)
......
......@@ -1355,6 +1355,16 @@ private void ParseModifiers(SyntaxListBuilder tokens)
}
return;
}
case SyntaxModifier.ReadOnly:
{
if (PeekToken(1).Kind == SyntaxKind.RefKeyword)
{
// readonly is not a modifier in "readonly ref", since "ref" is not a modifier.
return;
}
goto default;
}
default:
{
modTok = this.EatToken();
......@@ -6463,16 +6473,24 @@ private enum ParseTypeMode
ParseTypeMode mode = ParseTypeMode.Normal,
bool expectSizes = false)
{
if (mode == ParseTypeMode.Normal && !expectSizes && this.CurrentToken.Kind == SyntaxKind.RefKeyword)
if (mode == ParseTypeMode.Normal && !expectSizes)
{
var refKeyword = this.EatToken();
var type = ParseTypeCore(mode, expectSizes);
return this.CheckFeatureAvailability(_syntaxFactory.RefType(refKeyword, type), MessageID.IDS_FeatureRefLocalsReturns);
}
else
{
return ParseTypeCore(mode, expectSizes);
SyntaxToken readonlyKeyword = null;
if (this.CurrentToken.Kind == SyntaxKind.ReadOnlyKeyword && this.PeekToken(1).Kind == SyntaxKind.RefKeyword)
{
readonlyKeyword = this.EatToken();
readonlyKeyword = this.CheckFeatureAvailability(readonlyKeyword, MessageID.IDS_FeatureReadonlyReferences);
}
if (this.CurrentToken.Kind == SyntaxKind.RefKeyword)
{
var refKeyword = this.EatToken();
var type = ParseTypeCore(mode, expectSizes);
return this.CheckFeatureAvailability(_syntaxFactory.RefType(readonlyKeyword, refKeyword, type), MessageID.IDS_FeatureRefLocalsReturns);
}
}
return ParseTypeCore(mode, expectSizes);
}
private TypeSyntax ParseTypeCore(
......
......@@ -13,6 +13,7 @@ Microsoft.CodeAnalysis.CSharp.Conversion.IsThrow.get -> bool
Microsoft.CodeAnalysis.CSharp.Conversion.IsTupleConversion.get -> bool
Microsoft.CodeAnalysis.CSharp.Conversion.IsTupleLiteralConversion.get -> bool
Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp7 = 7 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion
Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp7_1 = 71 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion
Microsoft.CodeAnalysis.CSharp.LanguageVersion.Default = 0 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion
Microsoft.CodeAnalysis.CSharp.LanguageVersion.Latest = 2147483647 -> Microsoft.CodeAnalysis.CSharp.LanguageVersion
Microsoft.CodeAnalysis.CSharp.Syntax.AccessorDeclarationSyntax.ExpressionBody.get -> Microsoft.CodeAnalysis.CSharp.Syntax.ArrowExpressionClauseSyntax
......@@ -111,9 +112,12 @@ Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax.Update(Microsoft.CodeAn
Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax.WithExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax.WithRefKeyword(Microsoft.CodeAnalysis.SyntaxToken refKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.ReadOnlyKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.RefKeyword.get -> Microsoft.CodeAnalysis.SyntaxToken
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Type.get -> Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.WithReadOnlyKeyword(Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.WithRefKeyword(Microsoft.CodeAnalysis.SyntaxToken refKeyword) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax.WithType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax
......@@ -294,6 +298,7 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ParenthesizedVariableDesignat
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefExpression(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefExpressionSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.SyntaxToken readOnlyKeyword, Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.RefType(Microsoft.CodeAnalysis.SyntaxToken refKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.TypeSyntax type) -> Microsoft.CodeAnalysis.CSharp.Syntax.RefTypeSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.SingleVariableDesignation(Microsoft.CodeAnalysis.SyntaxToken identifier) -> Microsoft.CodeAnalysis.CSharp.Syntax.SingleVariableDesignationSyntax
static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ThrowExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax expression) -> Microsoft.CodeAnalysis.CSharp.Syntax.ThrowExpressionSyntax
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CSharp.Syntax
{
public partial class RefTypeSyntax
{
public RefTypeSyntax Update(SyntaxToken refKeyword, TypeSyntax type)
{
return Update(default(SyntaxToken), refKeyword, type);
}
}
}
namespace Microsoft.CodeAnalysis.CSharp
{
public partial class SyntaxFactory
{
/// <summary>Creates a new RefTypeSyntax instance.</summary>
public static RefTypeSyntax RefType(SyntaxToken refKeyword, TypeSyntax type)
{
return RefType(default(SyntaxToken), refKeyword, type);
}
}
}
......@@ -298,6 +298,12 @@
<summary>The ref modifier of a method's return value or a local.</summary>
</TypeComment>
<Kind Name="RefType"/>
<Field Name="ReadOnlyKeyword" Type="SyntaxToken" Optional="true">
<Kind Name="ReadOnlyKeyword"/>
<PropertyComment>
<summary>Gets the optional "readonly" keyword.</summary>
</PropertyComment>
</Field>
<Field Name="RefKeyword" Type="SyntaxToken">
<Kind Name="RefKeyword"/>
</Field>
......
......@@ -1239,7 +1239,7 @@ public void LangVersion()
parsedArgs = DefaultParse(new[] { "/langversion:latest", "a.cs" }, _baseDirectory);
parsedArgs.Errors.Verify();
Assert.Equal(LanguageVersion.Latest, parsedArgs.ParseOptions.SpecifiedLanguageVersion);
Assert.Equal(defaultVersion, parsedArgs.ParseOptions.LanguageVersion);
Assert.Equal(LanguageVersion.CSharp7_1, parsedArgs.ParseOptions.LanguageVersion);
parsedArgs = DefaultParse(new[] { "/langversion:iso-1", "a.cs" }, _baseDirectory);
parsedArgs.Errors.Verify();
......
......@@ -72,6 +72,7 @@
<Compile Include="Attributes\AttributeTests_Tuples.cs" />
<Compile Include="Attributes\AttributeTests_WellKnownAttributes.cs" />
<Compile Include="CodeGen\CodeGenCapturing.cs" />
<Compile Include="CodeGen\CodeGenReadonlyRefReturnTests.cs" />
<Compile Include="Emit\BinaryCompatibility.cs" />
<Compile Include="Emit\DesktopStrongNameProviderTests.cs" />
<Compile Include="Attributes\InternalsVisibleToAndStrongNameTests.cs" />
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
[CompilerTrait(CompilerFeature.ReadonlyReferences)]
public class ReadonlyRefReturnTests : CompilingTestBase
{
[Fact]
public void RefReturnArrayAccess()
{
var text = @"
class Program
{
static readonly ref int M()
{
return ref (new int[1])[0];
}
}
";
//PROTOTYPE(readonlyRefs): this should work for now because readonly is treated as regular ref
var comp = CompileAndVerify(text, parseOptions: TestOptions.Latest);
comp.VerifyIL("Program.M()", @"
{
// Code size 13 (0xd)
.maxstack 2
IL_0000: ldc.i4.1
IL_0001: newarr ""int""
IL_0006: ldc.i4.0
IL_0007: ldelema ""int""
IL_000c: ret
}");
}
}
}
......@@ -138,6 +138,7 @@
<Compile Include="Syntax\SyntaxTriviaListTests.cs" />
<Compile Include="Syntax\TrackNodeTests.cs" />
<Compile Include="TextExtensions.cs" />
<Compile Include="Parsing\ReadonlyRefReturns.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
......
......@@ -18,7 +18,7 @@ public class DeclarationParsingTests : ParsingTests
protected override SyntaxTree ParseTree(string text, CSharpParseOptions options)
{
return SyntaxFactory.ParseSyntaxTree(text, options);
return SyntaxFactory.ParseSyntaxTree(text, options ?? TestOptions.Latest);
}
[Fact]
......@@ -1977,6 +1977,34 @@ public void TestDelegateWithRefReturnType()
Assert.False(ds.SemicolonToken.IsMissing);
}
[CompilerTrait(CompilerFeature.ReadonlyReferences)]
[Fact]
public void TestDelegateWithReadonlyRefReturnType()
{
var text = "delegate readonly ref a b();";
var file = this.ParseFile(text, TestOptions.Latest);
Assert.NotNull(file);
Assert.Equal(1, file.Members.Count);
Assert.Equal(text, file.ToString());
Assert.Equal(0, file.Errors().Length);
Assert.Equal(SyntaxKind.DelegateDeclaration, file.Members[0].Kind());
var ds = (DelegateDeclarationSyntax)file.Members[0];
Assert.NotNull(ds.DelegateKeyword);
Assert.NotNull(ds.ReturnType);
Assert.Equal("readonly ref a", ds.ReturnType.ToString());
Assert.NotNull(ds.Identifier);
Assert.Equal("b", ds.Identifier.ToString());
Assert.NotNull(ds.ParameterList.OpenParenToken);
Assert.False(ds.ParameterList.OpenParenToken.IsMissing);
Assert.Equal(0, ds.ParameterList.Parameters.Count);
Assert.NotNull(ds.ParameterList.CloseParenToken);
Assert.False(ds.ParameterList.CloseParenToken.IsMissing);
Assert.NotNull(ds.SemicolonToken);
Assert.False(ds.SemicolonToken.IsMissing);
}
[Fact]
public void TestDelegateWithBuiltInReturnTypes()
{
......@@ -2466,6 +2494,52 @@ public void TestClassMethodWithRefReturn()
Assert.Equal(SyntaxKind.None, ms.SemicolonToken.Kind());
}
[CompilerTrait(CompilerFeature.ReadonlyReferences)]
[Fact]
public void TestClassMethodWithReadonlyRefReturn()
{
var text = "class a { readonly ref b X() { } }";
var file = this.ParseFile(text, TestOptions.Latest);
Assert.NotNull(file);
Assert.Equal(1, file.Members.Count);
Assert.Equal(text, file.ToString());
Assert.Equal(0, file.Errors().Length);
Assert.Equal(SyntaxKind.ClassDeclaration, file.Members[0].Kind());
var cs = (TypeDeclarationSyntax)file.Members[0];
Assert.Equal(0, cs.AttributeLists.Count);
Assert.Equal(0, cs.Modifiers.Count);
Assert.NotNull(cs.Keyword);
Assert.Equal(SyntaxKind.ClassKeyword, cs.Keyword.Kind());
Assert.NotNull(cs.Identifier);
Assert.Equal("a", cs.Identifier.ToString());
Assert.Null(cs.BaseList);
Assert.Equal(0, cs.ConstraintClauses.Count);
Assert.NotNull(cs.OpenBraceToken);
Assert.NotNull(cs.CloseBraceToken);
Assert.Equal(1, cs.Members.Count);
Assert.Equal(SyntaxKind.MethodDeclaration, cs.Members[0].Kind());
var ms = (MethodDeclarationSyntax)cs.Members[0];
Assert.Equal(0, ms.AttributeLists.Count);
Assert.NotNull(ms.ReturnType);
Assert.Equal("readonly ref b", ms.ReturnType.ToString());
Assert.NotNull(ms.Identifier);
Assert.Equal("X", ms.Identifier.ToString());
Assert.NotNull(ms.ParameterList.OpenParenToken);
Assert.False(ms.ParameterList.OpenParenToken.IsMissing);
Assert.Equal(0, ms.ParameterList.Parameters.Count);
Assert.NotNull(ms.ParameterList.CloseParenToken);
Assert.False(ms.ParameterList.CloseParenToken.IsMissing);
Assert.Equal(0, ms.ConstraintClauses.Count);
Assert.NotNull(ms.Body);
Assert.NotEqual(SyntaxKind.None, ms.Body.OpenBraceToken.Kind());
Assert.NotEqual(SyntaxKind.None, ms.Body.CloseBraceToken.Kind());
Assert.Equal(SyntaxKind.None, ms.SemicolonToken.Kind());
}
public void TestClassMethodWithRef()
{
var text = "class a { ref }";
......@@ -2494,6 +2568,36 @@ public void TestClassMethodWithRef()
Assert.Equal(SyntaxKind.IncompleteMember, cs.Members[0].Kind());
}
[CompilerTrait(CompilerFeature.ReadonlyReferences)]
[Fact]
public void TestClassMethodWithReadonlyRef()
{
var text = "class a { readonly ref }";
var file = this.ParseFile(text, parseOptions: TestOptions.Latest);
Assert.NotNull(file);
Assert.Equal(1, file.Members.Count);
Assert.Equal(text, file.ToString());
Assert.Equal(1, file.Errors().Length);
Assert.Equal(SyntaxKind.ClassDeclaration, file.Members[0].Kind());
var cs = (TypeDeclarationSyntax)file.Members[0];
Assert.Equal(0, cs.AttributeLists.Count);
Assert.Equal(0, cs.Modifiers.Count);
Assert.NotNull(cs.Keyword);
Assert.Equal(SyntaxKind.ClassKeyword, cs.Keyword.Kind());
Assert.NotNull(cs.Identifier);
Assert.Equal("a", cs.Identifier.ToString());
Assert.Null(cs.BaseList);
Assert.Equal(0, cs.ConstraintClauses.Count);
Assert.NotNull(cs.OpenBraceToken);
Assert.NotNull(cs.CloseBraceToken);
Assert.Equal(1, cs.Members.Count);
Assert.Equal(SyntaxKind.IncompleteMember, cs.Members[0].Kind());
}
private void TestClassMethodModifiers(params SyntaxKind[] modifiers)
{
var text = "class a { " + string.Join(" ", modifiers.Select(SyntaxFacts.GetText)) + " b X() { } }";
......@@ -3838,6 +3942,61 @@ public void TestClassPropertyWithRefReturn()
Assert.NotNull(ps.AccessorList.Accessors[1].SemicolonToken);
}
[CompilerTrait(CompilerFeature.ReadonlyReferences)]
[Fact]
public void TestClassPropertyWithReadonlyRefReturn()
{
var text = "class a { readonly ref b c { get; set; } }";
var file = this.ParseFile(text, TestOptions.Latest);
Assert.NotNull(file);
Assert.Equal(1, file.Members.Count);
Assert.Equal(text, file.ToString());
Assert.Equal(0, file.Errors().Length);
Assert.Equal(SyntaxKind.ClassDeclaration, file.Members[0].Kind());
var cs = (TypeDeclarationSyntax)file.Members[0];
Assert.Equal(0, cs.AttributeLists.Count);
Assert.Equal(0, cs.Modifiers.Count);
Assert.NotNull(cs.Keyword);
Assert.Equal(SyntaxKind.ClassKeyword, cs.Keyword.Kind());
Assert.NotNull(cs.Identifier);
Assert.Equal("a", cs.Identifier.ToString());
Assert.Null(cs.BaseList);
Assert.Equal(0, cs.ConstraintClauses.Count);
Assert.NotNull(cs.OpenBraceToken);
Assert.NotNull(cs.CloseBraceToken);
Assert.Equal(1, cs.Members.Count);
Assert.Equal(SyntaxKind.PropertyDeclaration, cs.Members[0].Kind());
var ps = (PropertyDeclarationSyntax)cs.Members[0];
Assert.Equal(0, ps.AttributeLists.Count);
Assert.Equal(0, ps.Modifiers.Count);
Assert.NotNull(ps.Type);
Assert.Equal("readonly ref b", ps.Type.ToString());
Assert.NotNull(ps.Identifier);
Assert.Equal("c", ps.Identifier.ToString());
Assert.NotNull(ps.AccessorList.OpenBraceToken);
Assert.NotNull(ps.AccessorList.CloseBraceToken);
Assert.Equal(2, ps.AccessorList.Accessors.Count);
Assert.Equal(0, ps.AccessorList.Accessors[0].AttributeLists.Count);
Assert.Equal(0, ps.AccessorList.Accessors[0].Modifiers.Count);
Assert.NotNull(ps.AccessorList.Accessors[0].Keyword);
Assert.Equal(SyntaxKind.GetKeyword, ps.AccessorList.Accessors[0].Keyword.Kind());
Assert.Null(ps.AccessorList.Accessors[0].Body);
Assert.NotNull(ps.AccessorList.Accessors[0].SemicolonToken);
Assert.Equal(0, ps.AccessorList.Accessors[1].AttributeLists.Count);
Assert.Equal(0, ps.AccessorList.Accessors[1].Modifiers.Count);
Assert.NotNull(ps.AccessorList.Accessors[1].Keyword);
Assert.Equal(SyntaxKind.SetKeyword, ps.AccessorList.Accessors[1].Keyword.Kind());
Assert.Null(ps.AccessorList.Accessors[1].Body);
Assert.NotNull(ps.AccessorList.Accessors[1].SemicolonToken);
}
[Fact]
public void TestClassPropertyWithBuiltInTypes()
{
......@@ -4726,6 +4885,74 @@ public void TestClassIndexerWithRefReturn()
Assert.NotNull(ps.AccessorList.Accessors[1].SemicolonToken);
}
[CompilerTrait(CompilerFeature.ReadonlyReferences)]
[Fact]
public void TestClassIndexerWithReadonlyRefReturn()
{
var text = "class a { readonly ref b this[c d] { get; set; } }";
var file = this.ParseFile(text, TestOptions.Latest);
Assert.NotNull(file);
Assert.Equal(1, file.Members.Count);
Assert.Equal(text, file.ToString());
Assert.Equal(0, file.Errors().Length);
Assert.Equal(SyntaxKind.ClassDeclaration, file.Members[0].Kind());
var cs = (TypeDeclarationSyntax)file.Members[0];
Assert.Equal(0, cs.AttributeLists.Count);
Assert.Equal(0, cs.Modifiers.Count);
Assert.NotNull(cs.Keyword);
Assert.Equal(SyntaxKind.ClassKeyword, cs.Keyword.Kind());
Assert.NotNull(cs.Identifier);
Assert.Equal("a", cs.Identifier.ToString());
Assert.Null(cs.BaseList);
Assert.Equal(0, cs.ConstraintClauses.Count);
Assert.NotNull(cs.OpenBraceToken);
Assert.NotNull(cs.CloseBraceToken);
Assert.Equal(1, cs.Members.Count);
Assert.Equal(SyntaxKind.IndexerDeclaration, cs.Members[0].Kind());
var ps = (IndexerDeclarationSyntax)cs.Members[0];
Assert.Equal(0, ps.AttributeLists.Count);
Assert.Equal(0, ps.Modifiers.Count);
Assert.NotNull(ps.Type);
Assert.Equal("readonly ref b", ps.Type.ToString());
Assert.NotNull(ps.ThisKeyword);
Assert.Equal("this", ps.ThisKeyword.ToString());
Assert.NotNull(ps.ParameterList); // used with indexer property
Assert.NotNull(ps.ParameterList.OpenBracketToken);
Assert.Equal(SyntaxKind.OpenBracketToken, ps.ParameterList.OpenBracketToken.Kind());
Assert.NotNull(ps.ParameterList.CloseBracketToken);
Assert.Equal(SyntaxKind.CloseBracketToken, ps.ParameterList.CloseBracketToken.Kind());
Assert.Equal(1, ps.ParameterList.Parameters.Count);
Assert.Equal(0, ps.ParameterList.Parameters[0].AttributeLists.Count);
Assert.Equal(0, ps.ParameterList.Parameters[0].Modifiers.Count);
Assert.NotNull(ps.ParameterList.Parameters[0].Type);
Assert.Equal("c", ps.ParameterList.Parameters[0].Type.ToString());
Assert.NotNull(ps.ParameterList.Parameters[0].Identifier);
Assert.Equal("d", ps.ParameterList.Parameters[0].Identifier.ToString());
Assert.NotNull(ps.AccessorList.OpenBraceToken);
Assert.NotNull(ps.AccessorList.CloseBraceToken);
Assert.Equal(2, ps.AccessorList.Accessors.Count);
Assert.Equal(0, ps.AccessorList.Accessors[0].AttributeLists.Count);
Assert.Equal(0, ps.AccessorList.Accessors[0].Modifiers.Count);
Assert.NotNull(ps.AccessorList.Accessors[0].Keyword);
Assert.Equal(SyntaxKind.GetKeyword, ps.AccessorList.Accessors[0].Keyword.Kind());
Assert.Null(ps.AccessorList.Accessors[0].Body);
Assert.NotNull(ps.AccessorList.Accessors[0].SemicolonToken);
Assert.Equal(0, ps.AccessorList.Accessors[1].AttributeLists.Count);
Assert.Equal(0, ps.AccessorList.Accessors[1].Modifiers.Count);
Assert.NotNull(ps.AccessorList.Accessors[1].Keyword);
Assert.Equal(SyntaxKind.SetKeyword, ps.AccessorList.Accessors[1].Keyword.Kind());
Assert.Null(ps.AccessorList.Accessors[1].Body);
Assert.NotNull(ps.AccessorList.Accessors[1].SemicolonToken);
}
[Fact]
public void TestClassIndexerWithMultipleParameters()
{
......@@ -5546,7 +5773,7 @@ class C1
}
}
";
var file = this.ParseFile(text, parseOptions: TestOptions.Regular);
var file = this.ParseFile(text);
Assert.Equal(0, file.Errors().Length);
}
......@@ -5567,7 +5794,7 @@ class C1
}
}
";
var file = this.ParseFile(text, parseOptions: TestOptions.Regular);
var file = this.ParseFile(text);
Assert.Equal(0, file.Errors().Length);
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Xunit;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit.Abstractions;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Parsing
{
[CompilerTrait(CompilerFeature.ReadonlyReferences)]
public class ReadonlyRefReturnsTests : ParsingTests
{
public ReadonlyRefReturnsTests(ITestOutputHelper output) : base(output) { }
protected override SyntaxTree ParseTree(string text, CSharpParseOptions options)
{
return SyntaxFactory.ParseSyntaxTree(text, options: options);
}
[Fact]
public void ReadonlyRefReturn_CSharp7()
{
var text = @"
unsafe class Program
{
delegate readonly ref int D1();
static readonly ref T M<T>()
{
return ref (new T[1])[0];
}
public virtual readonly ref int* P1 => throw null;
public readonly ref int[][] this[int i] => throw null;
}
";
var comp = CreateCompilationWithMscorlib45(text, parseOptions: TestOptions.Regular.WithLanguageVersion(LanguageVersion.CSharp7), options: TestOptions.UnsafeDebugDll);
comp.VerifyDiagnostics(
// (4,14): error CS8107: Feature 'readonly references' is not available in C# 7. Please use language version 71 or greater.
// delegate readonly ref int D1();
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "readonly").WithArguments("readonly references", "71").WithLocation(4, 14),
// (6,12): error CS8107: Feature 'readonly references' is not available in C# 7. Please use language version 71 or greater.
// static readonly ref T M<T>()
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "readonly").WithArguments("readonly references", "71").WithLocation(6, 12),
// (11,20): error CS8107: Feature 'readonly references' is not available in C# 7. Please use language version 71 or greater.
// public virtual readonly ref int* P1 => throw null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "readonly").WithArguments("readonly references", "71").WithLocation(11, 20),
// (13,12): error CS8107: Feature 'readonly references' is not available in C# 7. Please use language version 71 or greater.
// public readonly ref int[][] this[int i] => throw null;
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7, "readonly").WithArguments("readonly references", "71").WithLocation(13, 12)
);
}
[Fact]
public void ReadonlyRefReturn_Unexpected()
{
var text = @"
class Program
{
static void Main()
{
readonly ref int local = ref (new int[1])[0];
}
readonly ref int Field;
public static readonly ref Program operator +(Program x, Program y)
{
throw null;
}
// this parses fine
static async readonly ref Task M<T>()
{
throw null;
}
public readonly ref virtual int* P1 => throw null;
}
";
ParseAndValidate(text, TestOptions.Latest,
// (7,9): error CS0106: The modifier 'readonly' is not valid for this item
// readonly ref int local = ref (new int[1])[0];
Diagnostic(ErrorCode.ERR_BadMemberFlag, "readonly").WithArguments("readonly").WithLocation(7, 9),
// (10,27): error CS1003: Syntax error, '(' expected
// readonly ref int Field;
Diagnostic(ErrorCode.ERR_SyntaxError, ";").WithArguments("(", ";").WithLocation(10, 27),
// (10,27): error CS1026: ) expected
// readonly ref int Field;
Diagnostic(ErrorCode.ERR_CloseParenExpected, ";").WithLocation(10, 27),
// (12,41): error CS1519: Invalid token 'operator' in class, struct, or interface member declaration
// public static readonly ref Program operator +(Program x, Program y)
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "operator").WithArguments("operator").WithLocation(12, 41),
// (12,41): error CS1519: Invalid token 'operator' in class, struct, or interface member declaration
// public static readonly ref Program operator +(Program x, Program y)
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "operator").WithArguments("operator").WithLocation(12, 41),
// (13,5): error CS1519: Invalid token '{' in class, struct, or interface member declaration
// {
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(13, 5),
// (13,5): error CS1519: Invalid token '{' in class, struct, or interface member declaration
// {
Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(13, 5),
// (23,25): error CS1031: Type expected
// public readonly ref virtual int* P1 => throw null;
Diagnostic(ErrorCode.ERR_TypeExpected, "virtual").WithLocation(23, 25),
// (25,1): error CS1022: Type or namespace definition, or end-of-file expected
// }
Diagnostic(ErrorCode.ERR_EOFExpected, "}").WithLocation(25, 1)
);
}
}
}
......@@ -16,9 +16,10 @@ public static class TestOptions
public static readonly CSharpParseOptions Regular6 = Regular.WithLanguageVersion(LanguageVersion.CSharp6);
public static readonly CSharpParseOptions RegularWithDocumentationComments = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.Diagnose);
public static readonly CSharpParseOptions Latest = new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None).WithLanguageVersion(LanguageVersion.Latest);
private static readonly SmallDictionary<string, string> s_experimentalFeatures = new SmallDictionary<string, string> { };
public static readonly CSharpParseOptions ExperimentalParseOptions =
new CSharpParseOptions(kind: SourceCodeKind.Regular, documentationMode: DocumentationMode.None, languageVersion: LanguageVersion.CSharp7).WithFeatures(s_experimentalFeatures);
public static readonly CSharpParseOptions ExperimentalParseOptions = Latest.WithFeatures(s_experimentalFeatures);
// Enable pattern-switch translation even for switches that use no new syntax. This is used
// to help ensure compatibility of the semantics of the new switch binder with the old switch
......
......@@ -17,6 +17,7 @@ public enum CompilerFeature
Var,
Tuples,
RefLocalsReturns,
ReadonlyReferences,
OutVar,
Patterns,
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册