diff --git a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs
index 85bdacd13cc96..4c35bdbc31279 100644
--- a/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs
+++ b/src/Compilers/CSharp/Portable/Lowering/Instrumentation/DynamicAnalysisInjector.cs
@@ -590,10 +590,8 @@ private static Text.TextSpan SkipAttributes(SyntaxNode syntax)
return SkipAttributes(syntax, propertySyntax.AttributeLists, propertySyntax.Modifiers, default(SyntaxToken), propertySyntax.Type);
case SyntaxKind.DataPropertyDeclaration:
- {
- var dataProp = (DataPropertyDeclarationSyntax)syntax;
- return SkipAttributes(syntax, dataProp.AttributeLists, dataProp.Modifiers, dataProp.DataKeyword, dataProp.Type);
- }
+ Debug.Assert(false, "data properties cannot contain bodies");
+ break;
case SyntaxKind.GetAccessorDeclaration:
case SyntaxKind.SetAccessorDeclaration:
diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs
index d6794e6184813..5f0d56abddf4b 100644
--- a/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs
+++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxFacts.cs
@@ -174,6 +174,9 @@ public static bool IsInTypeOnlyContext(ExpressionSyntax node)
case PropertyDeclaration:
return ((PropertyDeclarationSyntax)parent).Type == node;
+ case DataPropertyDeclaration:
+ return ((DataPropertyDeclarationSyntax)parent).Type == node;
+
case DelegateDeclaration:
return ((DelegateDeclarationSyntax)parent).ReturnType == node;
@@ -254,7 +257,7 @@ public static bool IsInNamespaceOrTypeContext(ExpressionSyntax? node)
}
///
- /// Is the node the name of a named argument of an invocation, object creation expression,
+ /// Is the node the name of a named argument of an invocation, object creation expression,
/// constructor initializer, or element access, but not an attribute.
///
public static bool IsNamedArgumentName(SyntaxNode node)
diff --git a/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicAnalysisResourceTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicAnalysisResourceTests.cs
index 0b79f1f5edf3e..f4b18ac2c2bf2 100644
--- a/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicAnalysisResourceTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicAnalysisResourceTests.cs
@@ -281,7 +281,7 @@ public static void Main() // Method 0
{
Fred();
}
-
+
[Obsolete()]
static void Fred() // Method 1
{
@@ -341,7 +341,7 @@ ref int BamBam(ref int x) // Method 7
var reader = DynamicAnalysisDataReader.TryCreateFromPE(peReader, "");
VerifyDocuments(reader, reader.Documents,
- @"'C:\myproject\doc1.cs' A3-08-94-55-7C-64-8D-C7-61-7A-11-0B-4B-68-2C-3B-51-C3-C4-58 (SHA1)");
+ @"'C:\myproject\doc1.cs' A4-02-50-34-9F-CD-91-F7-CB-94-31-74-4C-E6-71-07-8E-8A-F9-DD (SHA1)");
Assert.Equal(15, reader.Methods.Length);
@@ -404,7 +404,7 @@ public static void Main() // Method 0
s.GPA = 2.3;
Operate(s);
}
-
+
static string Operate(Person p) // Method 1
{
switch (p)
@@ -611,10 +611,13 @@ static C() // Method 4
int Prop1 { get; } = 15;
static int Prop2 { get; } = 255;
+ [Obsolete]
+ data int Prop3 = 16;
}
";
- var c = CreateCompilation(Parse(source + InstrumentationHelperSource, @"C:\myproject\doc1.cs"));
+ var c = CreateCompilation(Parse(source + IsExternalInitTypeDefinition + InstrumentationHelperSource,
+ @"C:\myproject\doc1.cs", options: TestOptions.RegularPreview));
var peImage = c.EmitToArray(EmitOptions.Default.WithInstrumentationKinds(ImmutableArray.Create(InstrumentationKind.TestCoverage)));
var peReader = new PEReader(peImage);
@@ -640,6 +643,7 @@ static C() // Method 4
new SpanResult(27, 13, 27, 19, "Init()"),
new SpanResult(28, 13, 28, 24, "Init() + 12"),
new SpanResult(44, 25, 44, 27, "15"),
+ new SpanResult(47, 21, 47, 23, "16"),
new SpanResult(19, 8, 19, 16, "_z = 12"));
VerifySpans(reader, reader.Methods[4], sourceLines,
@@ -654,6 +658,7 @@ static C() // Method 4
new SpanResult(27, 13, 27, 19, "Init()"),
new SpanResult(28, 13, 28, 24, "Init() + 12"),
new SpanResult(44, 25, 44, 27, "15"),
+ new SpanResult(47, 21, 47, 23, "16"),
new SpanResult(36, 8, 36, 15, "_z = x"));
VerifySpans(reader, reader.Methods[6], sourceLines,
@@ -661,6 +666,7 @@ static C() // Method 4
new SpanResult(27, 13, 27, 19, "Init()"),
new SpanResult(28, 13, 28, 24, "Init() + 12"),
new SpanResult(44, 25, 44, 27, "15"),
+ new SpanResult(47, 21, 47, 23, "16"),
new SpanResult(41, 8, 41, 19, "_z = a + b"));
}
diff --git a/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.cs
index 1e18060ffb92a..f34d0ea901e7e 100644
--- a/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/Emit/DynamicAnalysis/DynamicInstrumentationTests.cs
@@ -16,6 +16,65 @@ namespace Microsoft.CodeAnalysis.CSharp.DynamicAnalysis.UnitTests
{
public class DynamicInstrumentationTests : CSharpTestBase
{
+ [Fact]
+ public void DataPropertyInitializer()
+ {
+ string source = @"
+using System;
+using System.Diagnostics.CodeAnalysis;
+
+class C
+{
+ data int P1;
+ data int P2 = 25;
+
+ public static void Main(string[] args)
+ {
+ new C();
+ Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload();
+ }
+}
+";
+ var verifier = CompileAndVerify(source + InstrumentationHelperSource + IsExternalInitTypeDefinition,
+ options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
+
+ // data accessors are implicit, therefore not instrumented
+ AssertNotInstrumented(verifier, "C.P1.get");
+ AssertNotInstrumented(verifier, "C.P1.init");
+
+ verifier.VerifyIL("C..ctor()", @"
+{
+ // Code size 71 (0x47)
+ .maxstack 5
+ .locals init (bool[] V_0)
+ IL_0000: ldsfld ""bool[][] .PayloadRoot0""
+ IL_0005: ldtoken ""C..ctor()""
+ IL_000a: ldelem.ref
+ IL_000b: stloc.0
+ IL_000c: ldloc.0
+ IL_000d: brtrue.s IL_0034
+ IL_000f: ldsfld ""System.Guid .MVID""
+ IL_0014: ldtoken ""C..ctor()""
+ IL_0019: ldtoken Source Document 0
+ IL_001e: ldsfld ""bool[][] .PayloadRoot0""
+ IL_0023: ldtoken ""C..ctor()""
+ IL_0028: ldelema ""bool[]""
+ IL_002d: ldc.i4.1
+ IL_002e: call ""bool[] Microsoft.CodeAnalysis.Runtime.Instrumentation.CreatePayload(System.Guid, int, int, ref bool[], int)""
+ IL_0033: stloc.0
+ IL_0034: ldloc.0
+ IL_0035: ldc.i4.0
+ IL_0036: ldc.i4.1
+ IL_0037: stelem.i1
+ IL_0038: ldarg.0
+ IL_0039: ldc.i4.s 25
+ IL_003b: stfld ""int C.k__BackingField""
+ IL_0040: ldarg.0
+ IL_0041: call ""object..ctor()""
+ IL_0046: ret
+}");
+ }
+
[Fact]
public void HelpersInstrumentation()
{
@@ -766,7 +825,7 @@ public static void Main(string[] args) // Metho
TestMain();
Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload();
}
-
+
static void TestMain() // Method 2
{
int x = Count;
@@ -873,11 +932,11 @@ public static void Main(string[] args) // Metho
TestMain();
Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload();
}
-
+
static void TestMain() // Method 2
{
new D().M1();
- }
+ }
}
public class D
@@ -971,7 +1030,7 @@ public static void Main(string[] args) // Metho
TestMain();
Microsoft.CodeAnalysis.Runtime.Instrumentation.FlushPayload();
}
-
+
#line 20 ""File2.cs""
static void TestMain() // Method 2
{
@@ -1442,7 +1501,7 @@ static void TestMain() // Method 2
s.GPA = s.Name switch { _ => 2.3 }; // switch expression is not instrumented
Operate(s);
}
-
+
static string Operate(Person p) // Method 3
{
switch (p)
@@ -1866,7 +1925,7 @@ File 1
public void IteratorCoverage()
{
string source = @"
-using System;
+using System;
public class Program
{
@@ -1879,11 +1938,11 @@ public static void Main(string[] args) // Metho
static void TestMain() // Method 2
{
foreach (var i in Goo())
- {
+ {
Console.WriteLine(i);
- }
+ }
foreach (var i in Goo())
- {
+ {
Console.WriteLine(i);
}
}
@@ -2280,14 +2339,14 @@ public void MissingMethodNeededForAnalysis()
string source = @"
namespace System
{
- public class Object { }
- public struct Int32 { }
- public struct Boolean { }
- public class String { }
- public class Exception { }
- public class ValueType { }
- public class Enum { }
- public struct Void { }
+ public class Object { }
+ public struct Int32 { }
+ public struct Boolean { }
+ public class String { }
+ public class Exception { }
+ public class ValueType { }
+ public class Enum { }
+ public struct Void { }
public class Guid { }
}
@@ -2397,7 +2456,7 @@ class C
{
[ExcludeFromCodeCoverage]
static void M1() { L1(); void L1() { new Action(() => { Console.WriteLine(1); }).Invoke(); } }
-
+
static void M2() { L2(); void L2() { new Action(() => { Console.WriteLine(2); }).Invoke(); } }
}
";
@@ -2561,16 +2620,16 @@ public void ExcludeFromCodeCoverageAttribute_LocalFunctionsAndLambdas_InAccessor
class C
{
[ExcludeFromCodeCoverage]
- int P1
- {
- get { L1(); void L1() { Console.WriteLine(1); } return 1; }
- set { L2(); void L2() { Console.WriteLine(2); } }
+ int P1
+ {
+ get { L1(); void L1() { Console.WriteLine(1); } return 1; }
+ set { L2(); void L2() { Console.WriteLine(2); } }
}
int P2
- {
- get { L3(); void L3() { Console.WriteLine(3); } return 3; }
- set { L4(); void L4() { Console.WriteLine(4); } }
+ {
+ get { L3(); void L3() { Console.WriteLine(3); } return 3; }
+ set { L4(); void L4() { Console.WriteLine(4); } }
}
}
";
@@ -2712,10 +2771,10 @@ class C
{
[ExcludeFromCodeCoverage]
int P1 { get => 1; set {} }
-
+
[ExcludeFromCodeCoverage]
event Action E1 { add { } remove { } }
-
+
int P2 { get => 1; set {} }
event Action E2 { add { } remove { } }
}
@@ -2842,7 +2901,7 @@ public void TestPartialMethodsWithImplementation()
public partial class Class1
{
partial void Method1(int x);
- public void Method2(int x)
+ public void Method2(int x)
{
Console.WriteLine($""Method2: x = {x}"");
Method1(x);
@@ -2944,7 +3003,7 @@ public void TestPartialMethodsWithoutImplementation()
public partial class Class1
{
partial void Method1(int x);
- public void Method2(int x)
+ public void Method2(int x)
{
Console.WriteLine($""Method2: x = {x}"");
Method1(x);
@@ -3391,7 +3450,7 @@ private static void AssertInstrumented(CompilationVerifier verifier, string qual
{
string il = verifier.VisualizeIL(qualifiedMethodName);
- // Tests using this helper are constructed such that instrumented methods contain a call to CreatePayload,
+ // Tests using this helper are constructed such that instrumented methods contain a call to CreatePayload,
// lambdas a reference to payload bool array.
bool instrumented = il.Contains("CreatePayload") || il.Contains("bool[]");
diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs
index 6ece292273c8e..b7a05b76f9c88 100644
--- a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs
+++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/RecordTests.cs
@@ -196,8 +196,8 @@ public void GeneratedProperties()
Assert.False(y.IsWriteOnly);
Assert.False(y.IsImplicitlyDeclared);
Assert.Equal(Accessibility.Public, y.DeclaredAccessibility);
- Assert.False(x.IsVirtual);
- Assert.False(x.IsStatic);
+ Assert.False(y.IsVirtual);
+ Assert.False(y.IsStatic);
Assert.Equal(c, y.ContainingType);
Assert.Equal(c, y.ContainingSymbol);
@@ -1736,6 +1736,150 @@ class C
);
}
+ [Fact]
+ public void DataProperties11()
+ {
+ var comp = CreateCompilation(@"
+abstract class C
+{
+ data int P1;
+ virtual data int P2;
+ abstract data int P3;
+}");
+ comp.VerifyDiagnostics();
+ var c = comp.GlobalNamespace.GetTypeMember("C");
+
+ var p1 = (SourcePropertySymbolBase)c.GetProperty("P1");
+ Assert.NotNull(p1.GetMethod);
+ Assert.Equal(MethodKind.PropertyGet, p1.GetMethod.MethodKind);
+ Assert.Equal(SpecialType.System_Int32, p1.Type.SpecialType);
+ Assert.False(p1.IsReadOnly);
+ Assert.False(p1.IsWriteOnly);
+ Assert.False(p1.IsImplicitlyDeclared);
+ Assert.Equal(Accessibility.Public, p1.DeclaredAccessibility);
+ Assert.False(p1.IsVirtual);
+ Assert.False(p1.IsStatic);
+ Assert.Equal(c, p1.ContainingType);
+ Assert.Equal(c, p1.ContainingSymbol);
+
+ var backing = p1.BackingField;
+ Debug.Assert(backing != null);
+ Assert.Equal(p1, backing.AssociatedSymbol);
+ Assert.Equal(c, backing.ContainingSymbol);
+ Assert.Equal(c, backing.ContainingType);
+ Assert.True(backing.IsImplicitlyDeclared);
+
+ var getAccessor = p1.GetMethod;
+ Assert.Equal(p1, getAccessor.AssociatedSymbol);
+ Assert.True(getAccessor.IsImplicitlyDeclared);
+ Assert.Equal(c, getAccessor.ContainingSymbol);
+ Assert.Equal(c, getAccessor.ContainingType);
+ Assert.Equal(Accessibility.Public, getAccessor.DeclaredAccessibility);
+
+ var setAccessor = p1.SetMethod;
+ Assert.Equal(p1, setAccessor.AssociatedSymbol);
+ Assert.True(setAccessor.IsImplicitlyDeclared);
+ Assert.Equal(c, setAccessor.ContainingSymbol);
+ Assert.Equal(c, setAccessor.ContainingType);
+ Assert.Equal(Accessibility.Public, setAccessor.DeclaredAccessibility);
+ Assert.True(setAccessor.IsInitOnly);
+
+ var p2 = (SourcePropertySymbolBase)c.GetProperty("P2");
+ Assert.NotNull(p2.GetMethod);
+ Assert.Equal(MethodKind.PropertyGet, p2.GetMethod.MethodKind);
+ Assert.Equal(SpecialType.System_Int32, p2.Type.SpecialType);
+ Assert.False(p2.IsReadOnly);
+ Assert.False(p2.IsWriteOnly);
+ Assert.False(p2.IsImplicitlyDeclared);
+ Assert.Equal(Accessibility.Public, p2.DeclaredAccessibility);
+ Assert.True(p2.IsVirtual);
+ Assert.False(p2.IsStatic);
+ Assert.Equal(c, p2.ContainingType);
+ Assert.Equal(c, p2.ContainingSymbol);
+
+ backing = p2.BackingField;
+ Debug.Assert(backing != null);
+ Assert.Equal(p2, backing.AssociatedSymbol);
+ Assert.Equal(c, backing.ContainingSymbol);
+ Assert.Equal(c, backing.ContainingType);
+ Assert.True(backing.IsImplicitlyDeclared);
+
+ getAccessor = p2.GetMethod;
+ Assert.Equal(p2, getAccessor.AssociatedSymbol);
+ Assert.True(getAccessor.IsImplicitlyDeclared);
+ Assert.Equal(c, getAccessor.ContainingSymbol);
+ Assert.Equal(c, getAccessor.ContainingType);
+
+ setAccessor = p2.SetMethod;
+ Assert.Equal(p2, setAccessor.AssociatedSymbol);
+ Assert.True(setAccessor.IsImplicitlyDeclared);
+ Assert.Equal(c, setAccessor.ContainingSymbol);
+ Assert.Equal(c, setAccessor.ContainingType);
+ Assert.Equal(Accessibility.Public, setAccessor.DeclaredAccessibility);
+ Assert.True(setAccessor.IsInitOnly);
+
+ var p3 = (SourcePropertySymbolBase)c.GetProperty("P3");
+ Assert.NotNull(p3.GetMethod);
+ Assert.Equal(MethodKind.PropertyGet, p3.GetMethod.MethodKind);
+ Assert.Equal(SpecialType.System_Int32, p3.Type.SpecialType);
+ Assert.False(p3.IsReadOnly);
+ Assert.False(p3.IsWriteOnly);
+ Assert.False(p3.IsImplicitlyDeclared);
+ Assert.Equal(Accessibility.Public, p3.DeclaredAccessibility);
+ Assert.False(p3.IsVirtual);
+ Assert.True(p3.IsAbstract);
+ Assert.False(p3.IsStatic);
+ Assert.Equal(c, p3.ContainingType);
+ Assert.Equal(c, p3.ContainingSymbol);
+
+ Assert.Null(p3.BackingField);
+
+ getAccessor = p3.GetMethod;
+ Assert.True(getAccessor.IsAbstract);
+ Assert.Equal(p3, getAccessor.AssociatedSymbol);
+ Assert.True(getAccessor.IsImplicitlyDeclared);
+ Assert.Equal(c, getAccessor.ContainingSymbol);
+ Assert.Equal(c, getAccessor.ContainingType);
+
+ setAccessor = p3.SetMethod;
+ Assert.True(setAccessor.IsAbstract);
+ Assert.Equal(p3, setAccessor.AssociatedSymbol);
+ Assert.True(setAccessor.IsImplicitlyDeclared);
+ Assert.Equal(c, setAccessor.ContainingSymbol);
+ Assert.Equal(c, setAccessor.ContainingType);
+ Assert.Equal(Accessibility.Public, setAccessor.DeclaredAccessibility);
+ Assert.True(setAccessor.IsInitOnly);
+ }
+
+ [Fact]
+ public void DataProperties12()
+ {
+ var src = @"
+class C
+{
+ data dynamic P;
+}";
+ var comp = CreateCompilation(src);
+ comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_DynamicAttribute);
+ comp.VerifyDiagnostics(
+ // (4,10): error CS1980: Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference?
+ // data dynamic P;
+ Diagnostic(ErrorCode.ERR_DynamicAttributeMissing, "dynamic").WithArguments("System.Runtime.CompilerServices.DynamicAttribute").WithLocation(4, 10)
+ );
+
+ CompileAndVerify(new[] { src, IsExternalInitTypeDefinition },
+ parseOptions: TestOptions.RegularPreview,
+ symbolValidator: m =>
+ {
+ var p = m.GlobalNamespace.GetTypeMember("C").GetMember("P");
+ var attr = Assert.Single(p.GetAttributes()).AttributeClass!;
+ Assert.Equal(
+ "System.Runtime.CompilerServices.DynamicAttribute",
+ attr.ToTestDisplayString());
+ Assert.NotEqual(m.ContainingAssembly, attr.ContainingAssembly);
+ });
+ }
+
[Fact]
public void DataPropertiesInterface()
{
@@ -1818,6 +1962,27 @@ class C5 : C4
);
}
+ [Fact]
+ public void DataPropertiesSealed()
+ {
+ var src = @"
+abstract class C1
+{
+ abstract data int P1;
+}
+class C2 : C1
+{
+ sealed override data int P1;
+}";
+
+ var comp = CreateCompilation(src);
+ comp.VerifyDiagnostics(
+ // (8,30): error CS0106: The modifier 'sealed' is not valid for this item
+ // sealed override data int P1;
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "P1").WithArguments("sealed").WithLocation(8, 30)
+ );
+ }
+
[Fact]
public void GenericRecord()
{