From fa105f2c2e309150d72230962d5b51bf5d390f02 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 7 May 2020 21:04:37 -0700 Subject: [PATCH 1/9] Add public API for IsInitOnly --- .../SymbolDisplayVisitor.Members.cs | 3 +- .../Symbols/PublicModel/MethodSymbol.cs | 8 + .../Semantic/Semantics/InitOnlyMemberTests.cs | 142 +++++++++++++++++- .../Symbols/Retargeting/RetargetingTests.cs | 34 +++++ .../Core/Portable/PublicAPI.Unshipped.txt | 1 + .../Core/Portable/Symbols/IMethodSymbol.cs | 6 + .../Portable/Symbols/MethodSymbol.vb | 7 + ...dataAsSourceService.WrappedMethodSymbol.cs | 1 + .../CodeGenerationSymbolFactory.cs | 3 +- .../CodeGenerationAbstractMethodSymbol.cs | 1 + .../CodeGenerationConstructedMethodSymbol.cs | 1 + .../CodeGenerationConstructorSymbol.cs | 1 + .../Symbols/CodeGenerationConversionSymbol.cs | 1 + .../Symbols/CodeGenerationDestructorSymbol.cs | 1 + .../Symbols/CodeGenerationMethodSymbol.cs | 5 +- .../Symbols/CodeGenerationOperatorSymbol.cs | 1 + 16 files changed, 211 insertions(+), 5 deletions(-) diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs index 5acca72f2cab8..e02907162f5c7 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs @@ -171,8 +171,7 @@ public override void VisitProperty(IPropertySymbol symbol) private static bool IsInitOnly(IMethodSymbol symbol) { - // PROTOTYPE(init-only): adjust SymbolDisplayVisitor once we have a public IsInitOnly API - return (symbol as Symbols.PublicModel.MethodSymbol)?.UnderlyingMethodSymbol.IsInitOnly == true; + return symbol?.IsInitOnly == true; } private void AddPropertyNameAndParameters(IPropertySymbol symbol) diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs index b3d053baa4897..055076a49c61f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/MethodSymbol.cs @@ -139,6 +139,14 @@ bool IMethodSymbol.IsReadOnly } } + bool IMethodSymbol.IsInitOnly + { + get + { + return _underlying.IsInitOnly; + } + } + IMethodSymbol IMethodSymbol.OriginalDefinition { get diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs index 1d876f0a35100..bbe8db601f0b8 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs @@ -48,6 +48,9 @@ public class C var property = (PropertySymbol)comp.GlobalNamespace.GetMember("C.Property"); Assert.False(property.GetMethod.IsInitOnly); Assert.True(property.SetMethod.IsInitOnly); + IPropertySymbol publicProperty = property.GetPublicSymbol(); + Assert.False(publicProperty.GetMethod.IsInitOnly); + Assert.True(publicProperty.SetMethod.IsInitOnly); } [Fact] @@ -108,12 +111,15 @@ public class C var property = (PropertySymbol)comp.GlobalNamespace.GetMember("C.Property"); Assert.False(property.SetMethod.IsInitOnly); + Assert.False(property.GetPublicSymbol().SetMethod.IsInitOnly); var property2 = (PropertySymbol)comp.GlobalNamespace.GetMember("C.Property2"); Assert.True(property2.SetMethod.IsInitOnly); + Assert.True(property2.GetPublicSymbol().SetMethod.IsInitOnly); var property3 = (PropertySymbol)comp.GlobalNamespace.GetMember("C.Property3"); Assert.True(property3.SetMethod.IsInitOnly); + Assert.True(property3.GetPublicSymbol().SetMethod.IsInitOnly); } [Fact] @@ -302,7 +308,9 @@ void M() var property = (PropertySymbol)comp.GlobalNamespace.GetTypeMember("Derived").BaseTypeNoUseSiteDiagnostics.GetMember("Property"); Assert.False(property.GetMethod.IsInitOnly); + Assert.False(property.GetPublicSymbol().GetMethod.IsInitOnly); Assert.True(property.SetMethod.IsInitOnly); + Assert.True(property.GetPublicSymbol().SetMethod.IsInitOnly); } [Fact] @@ -331,7 +339,9 @@ public class CWithoutInit : I // 1 var property = (PropertySymbol)comp.GlobalNamespace.GetMember("I.Property"); Assert.False(property.GetMethod.IsInitOnly); + Assert.False(property.GetPublicSymbol().GetMethod.IsInitOnly); Assert.True(property.SetMethod.IsInitOnly); + Assert.True(property.GetPublicSymbol().SetMethod.IsInitOnly); } [Fact] @@ -588,7 +598,9 @@ public string RegularProperty2 var property = (PropertySymbol)comp.GlobalNamespace.GetMember("C.Property"); Assert.False(property.GetMethod.IsInitOnly); + Assert.False(property.GetPublicSymbol().GetMethod.IsInitOnly); Assert.True(property.SetMethod.IsInitOnly); + Assert.True(property.GetPublicSymbol().SetMethod.IsInitOnly); } [Fact] @@ -773,8 +785,9 @@ public class C var property = (PropertySymbol)comp.GlobalNamespace.GetMember("C.Property"); Assert.False(property.GetMethod.IsInitOnly); - // PROTOTYPE(init-only): confirm during public API discussion for IsInitOnly + Assert.False(property.GetPublicSymbol().GetMethod.IsInitOnly); Assert.False(property.SetMethod.IsInitOnly); + Assert.False(property.GetPublicSymbol().SetMethod.IsInitOnly); } [Fact] @@ -1075,6 +1088,7 @@ void symbolValidator(ModuleSymbol m) var getter = property.GetMethod; Assert.Empty(property.GetMethod.ReturnTypeWithAnnotations.CustomModifiers); Assert.False(getter.IsInitOnly); + Assert.False(getter.GetPublicSymbol().IsInitOnly); var getterAttributes = getter.GetAttributes().Select(a => a.ToString()); if (isSource) { @@ -1087,6 +1101,7 @@ void symbolValidator(ModuleSymbol m) var setter = property.SetMethod; Assert.True(setter.IsInitOnly); + Assert.True(setter.GetPublicSymbol().IsInitOnly); var setterAttributes = property.SetMethod.GetAttributes().Select(a => a.ToString()); var modifier = property.SetMethod.ReturnTypeWithAnnotations.CustomModifiers.Single(); Assert.Equal("System.Runtime.CompilerServices.IsExternalInit", modifier.Modifier.ToTestDisplayString()); @@ -1986,6 +2001,86 @@ public event System.Action Event }); } + [Fact] + public void EventAccessorsAreNotInitOnly() + { + string source = @" +public class C +{ + public event System.Action Event + { + add { } + remove { } + } +} +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + + var eventSymbol = comp.GlobalNamespace.GetMember("C.Event"); + Assert.False(eventSymbol.AddMethod.IsInitOnly); + Assert.False(eventSymbol.GetPublicSymbol().AddMethod.IsInitOnly); + Assert.False(eventSymbol.RemoveMethod.IsInitOnly); + Assert.False(eventSymbol.GetPublicSymbol().RemoveMethod.IsInitOnly); + } + + [Fact] + public void ConstructorsAreNotInitOnly() + { + string source = @" +public class C +{ + public C() { } + ~C() { } +} +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + + var constructor = comp.GlobalNamespace.GetMember("C..ctor"); + Assert.False(constructor.IsInitOnly); + Assert.False(constructor.GetPublicSymbol().IsInitOnly); + + var destructor = comp.GlobalNamespace.GetMember("C.Finalize"); + Assert.False(destructor.IsInitOnly); + Assert.False(destructor.GetPublicSymbol().IsInitOnly); + } + + [Fact] + public void InitOnlyOnMembersOfRecords() + { + string source = @" +public data class C(int i) +{ + void M() { } +} +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + + var cMembers = comp.GlobalNamespace.GetMember("C").GetMembers(); + // PROTOTYPE(init-only): expecting an 'init' setter + AssertEx.SetEqual(new[] { + "System.Int32 C.k__BackingField", + "System.Int32 C.i.get", + "System.Int32 C.i { get; }", + "void C.M()", + "System.Boolean C.Equals(C? )", + "System.Boolean C.Equals(System.Object? )", + "System.Int32 C.GetHashCode()", + "C..ctor(System.Int32 i)" }, cMembers.ToTestDisplayStrings()); + + foreach (var member in cMembers) + { + if (member is MethodSymbol method) + { + bool isSetter = method.MethodKind == MethodKind.PropertySet; + Assert.Equal(isSetter, method.IsInitOnly); + Assert.Equal(isSetter, method.GetPublicSymbol().IsInitOnly); + } + } + } + [Fact] public void IndexerWithInitOnly() { @@ -2897,6 +2992,7 @@ void M2() // PROTOTYPE(init-only): decoding should be more restrictive var method = (PEMethodSymbol)comp.GlobalNamespace.GetMember("C.M"); Assert.False(method.IsInitOnly); + Assert.False(method.GetPublicSymbol().IsInitOnly); Assert.False(method.HasUseSiteError); // PROTOTYPE(init-only): expect true Assert.False(method.ReturnType.IsErrorType()); // PROTOTYPE(init-only): expect true } @@ -3023,6 +3119,7 @@ void M(C c, ref int i) Assert.False(property0.GetMethod.HasUseSiteError); Assert.True(property0.SetMethod.HasUseSiteError); Assert.False(property0.SetMethod.IsInitOnly); + Assert.False(property0.GetPublicSymbol().SetMethod.IsInitOnly); } [Fact] @@ -3108,6 +3205,7 @@ void M(C c, ref int i) Assert.True(property0.SetMethod.HasUseSiteError); Assert.False(property0.SetMethod.IsInitOnly); + Assert.False(property0.GetPublicSymbol().SetMethod.IsInitOnly); Assert.True(property0.SetMethod.Parameters[0].Type.IsErrorType()); } @@ -3196,6 +3294,7 @@ void M(C c, ref int i) Assert.True(property0.SetMethod.HasUseSiteError); Assert.False(property0.SetMethod.IsInitOnly); + Assert.False(property0.GetPublicSymbol().SetMethod.IsInitOnly); Assert.True(property0.SetMethod.Parameters[0].Type.IsErrorType()); } @@ -3255,8 +3354,10 @@ public class Derived : C // PROTOTYPE(init-only): getter should have use-site error var property = (PEPropertySymbol)comp.GlobalNamespace.GetMember("C.Property"); Assert.False(property.GetMethod.IsInitOnly); + Assert.False(property.GetPublicSymbol().GetMethod.IsInitOnly); Assert.False(property.GetMethod.HasUseSiteError); Assert.False(property.SetMethod.IsInitOnly); + Assert.False(property.GetPublicSymbol().SetMethod.IsInitOnly); Assert.False(property.SetMethod.HasUseSiteError); } @@ -3309,5 +3410,44 @@ static D() Diagnostic(ErrorCode.ERR_BaseInStaticMeth, "base").WithLocation(17, 9) ); } + + [Fact] + public void LocalFunctionsAreNotInitOnly() + { + var comp = CreateCompilation(new[] { @" +public class C +{ + delegate void Delegate(); + + void M() + { + local(); + void local() { } + } +} +", IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview); + + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var model = comp.GetSemanticModel(tree); + + var localFunctionSyntax = tree.GetRoot().DescendantNodes().OfType().Single(); + var localFunctionSymbol = model.GetDeclaredSymbol(localFunctionSyntax).GetSymbol(); + Assert.False(localFunctionSymbol.IsInitOnly); + Assert.False(localFunctionSymbol.GetPublicSymbol().IsInitOnly); + + var delegateSyntax = tree.GetRoot().DescendantNodes().OfType().Single(); + var delegateMemberSymbols = model.GetDeclaredSymbol(delegateSyntax).GetSymbol().GetMembers(); + Assert.True(delegateMemberSymbols.All(m => m is SourceDelegateMethodSymbol)); + foreach (var member in delegateMemberSymbols) + { + if (member is MethodSymbol method) + { + Assert.False(method.IsInitOnly); + Assert.False(method.GetPublicSymbol().IsInitOnly); + } + } + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs index 1544c145b3c63..d2a7795bfaacb 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs @@ -13,6 +13,7 @@ using Roslyn.Test.Utilities; using Xunit; using Utils = Microsoft.CodeAnalysis.CSharp.UnitTests.CompilationUtils; +using Microsoft.CodeAnalysis.Test.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Retargeting { @@ -120,6 +121,39 @@ object this[I index] RetargetingSymbolChecker.CheckSymbols(sourceNamespace.GetMember("C"), retargetingNamespace.GetMember("C")); } + [Fact, CompilerTrait(CompilerFeature.InitOnlySetters)] + public void RetargetProperties_WithInitOnlySetter() + { + var source = +@"interface I +{ + object Property { get; init; } +}"; + var compilation = CreateCompilation(source); + + var sourceModule = compilation.SourceModule; + var sourceAssembly = (SourceAssemblySymbol)sourceModule.ContainingAssembly; + + var retargetingAssembly = new RetargetingAssemblySymbol(sourceAssembly, isLinked: false); + retargetingAssembly.SetCorLibrary(sourceAssembly.CorLibrary); + var retargetingModule = retargetingAssembly.Modules[0]; + var retargetingNamespace = retargetingModule.GlobalNamespace; + + var property = retargetingNamespace.GetMember("I.Property"); + MethodSymbol getMethod = property.GetMethod; + MethodSymbol setMethod = property.SetMethod; + + Assert.Equal("System.Object I.Property { get; init; }", property.ToTestDisplayString()); + Assert.Equal("void modreq(System.Runtime.CompilerServices.IsExternalInit[missing]) I.Property.init", + setMethod.ToTestDisplayString()); + + Assert.False(getMethod.IsInitOnly); + Assert.False(getMethod.GetPublicSymbol().IsInitOnly); + + Assert.True(setMethod.IsInitOnly); + Assert.True(setMethod.GetPublicSymbol().IsInitOnly); + } + [Fact] public void RetargetFields() { diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 56ece4fe117f8..07dd0c9667c03 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -12,6 +12,7 @@ Microsoft.CodeAnalysis.GeneratorDriver.AddGenerators(System.Collections.Immutabl Microsoft.CodeAnalysis.GeneratorDriver.RemoveGenerators(System.Collections.Immutable.ImmutableArray generators) -> Microsoft.CodeAnalysis.GeneratorDriver Microsoft.CodeAnalysis.GeneratorDriver.RunFullGeneration(Microsoft.CodeAnalysis.Compilation compilation, out Microsoft.CodeAnalysis.Compilation outputCompilation, out System.Collections.Immutable.ImmutableArray diagnostics, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver Microsoft.CodeAnalysis.GeneratorDriver.TryApplyEdits(Microsoft.CodeAnalysis.Compilation compilation, out Microsoft.CodeAnalysis.Compilation outputCompilation, out bool success, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> Microsoft.CodeAnalysis.GeneratorDriver +Microsoft.CodeAnalysis.IMethodSymbol.IsInitOnly.get -> bool Microsoft.CodeAnalysis.INamedTypeSymbol.NativeIntegerUnderlyingType.get -> Microsoft.CodeAnalysis.INamedTypeSymbol Microsoft.CodeAnalysis.ISourceGenerator Microsoft.CodeAnalysis.ISourceGenerator.Execute(Microsoft.CodeAnalysis.SourceGeneratorContext context) -> void diff --git a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs index 07ecbf42b6e3f..16b5d4c0694d1 100644 --- a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs @@ -140,6 +140,12 @@ public interface IMethodSymbol : ISymbol /// bool IsReadOnly { get; } + /// + /// 'init' set accessors can only be invoked during construction or in the initialization phase + /// that follows construction. + /// + bool IsInitOnly { get; } + /// /// Get the original definition of this symbol. If this symbol is derived from another /// symbol by (say) type substitution, this gets the original symbol, as it was defined in diff --git a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb index ca775fd5df0be..2c4ecdd50701e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb @@ -111,6 +111,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + ' PROTOTYPE(init-only) VB will be able to consume 'init' set accessors + Private ReadOnly Property IMethodSymbol_IsInitOnly As Boolean Implements IMethodSymbol.IsInitOnly + Get + Return False + End Get + End Property + ''' ''' Returns true if this method has no return type; i.e., is a Sub instead of a Function. ''' diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs index 51bddf7bc655e..b989a83c6495c 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs @@ -28,6 +28,7 @@ public WrappedMethodSymbol(IMethodSymbol methodSymbol, bool canImplementImplicit public IMethodSymbol ConstructedFrom => _symbol.ConstructedFrom; public bool IsReadOnly => _symbol.IsReadOnly; + public bool IsInitOnly => _symbol.IsInitOnly; // TODO2: test MetadataAsSource public ImmutableArray ExplicitInterfaceImplementations { diff --git a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs index 0c6c28d5df475..fc45d5693f829 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs @@ -156,7 +156,8 @@ internal static IMethodSymbol CreateMethodSymbol( ImmutableArray returnTypeAttributes = default, MethodKind methodKind = MethodKind.Ordinary) { - var result = new CodeGenerationMethodSymbol(containingType, attributes, accessibility, modifiers, returnType, refKind, explicitInterfaceImplementations, name, typeParameters, parameters, returnTypeAttributes, methodKind); + // TODO2 + var result = new CodeGenerationMethodSymbol(containingType, attributes, accessibility, modifiers, returnType, refKind, isInitOnly: false, explicitInterfaceImplementations, name, typeParameters, parameters, returnTypeAttributes, methodKind); CodeGenerationMethodInfo.Attach(result, modifiers.IsNew, modifiers.IsUnsafe, modifiers.IsPartial, modifiers.IsAsync, statements, handlesExpressions); return result; } diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs index 5572afe1ea4d3..f863dfaa1ff5b 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs @@ -39,6 +39,7 @@ protected CodeGenerationAbstractMethodSymbol( public abstract ImmutableArray Parameters { get; } public abstract IMethodSymbol ConstructedFrom { get; } public abstract bool IsReadOnly { get; } + public abstract bool IsInitOnly { get; } public abstract IMethodSymbol OverriddenMethod { get; } public abstract IMethodSymbol ReducedFrom { get; } public abstract ITypeSymbol GetTypeInferredDuringReduction(ITypeParameterSymbol reducedFromTypeParameter); diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs index 2b7c0cdbda824..cacc6db5cd606 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs @@ -67,6 +67,7 @@ public override ImmutableArray Parameters public override IMethodSymbol ConstructedFrom => _constructedFrom; public override bool IsReadOnly => _constructedFrom.IsReadOnly; + public override bool IsInitOnly => _constructedFrom.IsInitOnly; public override IMethodSymbol OverriddenMethod => // TODO(cyrusn): Construct this. diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs index 6b1ece917a28e..73072289894c9 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs @@ -21,6 +21,7 @@ public CodeGenerationConstructorSymbol( modifiers, returnType: null, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: string.Empty, typeParameters: ImmutableArray.Empty, diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs index 3cc466d22f548..588b01a667089 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs @@ -24,6 +24,7 @@ public CodeGenerationConversionSymbol( modifiers, returnType: toType, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: isImplicit ? WellKnownMemberNames.ImplicitConversionName : diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs index 06c7e8dbf81ec..8bc4bbeb66271 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs @@ -17,6 +17,7 @@ public CodeGenerationDestructorSymbol( default, returnType: null, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: string.Empty, typeParameters: ImmutableArray.Empty, diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs index c5fa259d127f2..b49e790417ff6 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs @@ -23,6 +23,7 @@ public CodeGenerationMethodSymbol( DeclarationModifiers modifiers, ITypeSymbol returnType, RefKind refKind, + bool isInitOnly, ImmutableArray explicitInterfaceImplementations, string name, ImmutableArray typeParameters, @@ -33,6 +34,7 @@ public CodeGenerationMethodSymbol( { this.ReturnType = returnType; this.RefKind = refKind; + this.IsInitOnly = isInitOnly; this.TypeParameters = typeParameters.NullToEmpty(); this.Parameters = parameters.NullToEmpty(); this.MethodKind = methodKind; @@ -45,7 +47,7 @@ protected override CodeGenerationSymbol Clone() { var result = new CodeGenerationMethodSymbol(this.ContainingType, this.GetAttributes(), this.DeclaredAccessibility, this.Modifiers, - this.ReturnType, this.RefKind, this.ExplicitInterfaceImplementations, + this.ReturnType, this.RefKind, this.IsInitOnly, this.ExplicitInterfaceImplementations, this.Name, this.TypeParameters, this.Parameters, this.GetReturnTypeAttributes(), this.MethodKind); @@ -89,6 +91,7 @@ public override ImmutableArray TypeArguments public override IMethodSymbol ConstructedFrom => this; public override bool IsReadOnly => Modifiers.IsReadOnly; + public override bool IsInitOnly { get; } public override IMethodSymbol OverriddenMethod => null; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs index c67847ce70190..12ff7668b320e 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs @@ -25,6 +25,7 @@ public CodeGenerationOperatorSymbol( modifiers, returnType: returnType, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: GetMetadataName(operatorKind), typeParameters: ImmutableArray.Empty, From 5af14a63e17b8f239a54467ebe8b3d166edfe8a3 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Thu, 7 May 2020 22:20:13 -0700 Subject: [PATCH 2/9] Fix code generation on init-only property --- .../GenerateOverridesTests.cs | 52 +++++++++++++++++++ .../ImplementInterfaceTests.cs | 24 +++++++++ .../CodeGeneration/CodeGenerationTests.cs | 3 ++ .../MetadataAsSourceTests.CSharp.cs | 24 +++++++++ .../NavigationBar/GenerateEventHandlerItem.vb | 1 + .../NavigationBar/GenerateFinalizerItem.vb | 1 + ...FunctionToMethodCodeRefactoringProvider.cs | 1 + ...harpMethodExtractor.CSharpCodeGenerator.cs | 1 + .../CSharpGenerateConversionService.cs | 1 + ...AbstractPartialMethodCompletionProvider.cs | 1 + ...ymousTypeToClassCodeRefactoringProvider.cs | 2 +- ...ertTupleToStructCodeRefactoringProvider.cs | 1 + .../AbstractExtractInterfaceService.cs | 1 + ...ractGenerateEqualsAndGetHashCodeService.cs | 1 + ...tGenerateDeconstructMethodService.State.cs | 1 + .../AbstractGenerateMethodService.State.cs | 1 + ...arameterizedMemberService.SignatureInfo.cs | 1 + ...dataAsSourceService.WrappedMethodSymbol.cs | 2 +- ...ethodExtractor.VisualBasicCodeGenerator.vb | 1 + .../VisualBasicGenerateConversionService.vb | 1 + .../CodeGeneration/PropertyGenerator.cs | 3 +- .../CodeGenerationSymbolFactory.cs | 19 ++++--- .../Symbols/CodeGenerationMethodSymbol.cs | 6 ++- .../Extensions/IMethodSymbolExtensions.cs | 2 + ...xGeneratorExtensions_CreateEqualsMethod.cs | 1 + 25 files changed, 141 insertions(+), 11 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs b/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs index 8e3822e6db2d4..4348cbde6eb0f 100644 --- a/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs @@ -121,6 +121,58 @@ public override ref int X() }", new[] { "X", "Y", "this[]" }); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateOverrides)] + public async Task TestInitOnlyProperty() + { + await TestWithPickMembersDialogAsync( +@" +class Base +{ + public virtual int Property { init => throw new NotImplementedException(); } +} + +class Derived : Base +{ + [||] +}", +@" +class Base +{ + public virtual int Property { init => throw new NotImplementedException(); } +} + +class Derived : Base +{ + public override int Property { init => base.Property = value; } +}", new[] { "Property" }); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateOverrides)] + public async Task TestInitOnlyIndexer() + { + await TestWithPickMembersDialogAsync( +@" +class Base +{ + public virtual int this[int i] { init => throw new NotImplementedException(); } +} + +class Derived : Base +{ + [||] +}", +@" +class Base +{ + public virtual int this[int i] { init => throw new NotImplementedException(); } +} + +class Derived : Base +{ + public override int this[int i] { init => base[i] = value; } +}", new[] { "this[]" }); + } + [WorkItem(21601, "https://github.com/dotnet/roslyn/issues/21601")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateOverrides)] public async Task TestMissingInStaticClass1() diff --git a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs index a1aa1321cf4ee..f624ba96b474c 100644 --- a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs @@ -8417,6 +8417,30 @@ void I.M2() }", index: 2); } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] + public async Task ImplementInitOnlyProperty() + { + await TestInRegularAndScriptAsync(@" +interface I +{ + int Property { get; init; } +} + +class C : [|I|] +{ +}", +@" +interface I +{ + int Property { get; init; } +} + +class C : [|I|] +{ + public int Property { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } +}"); + } + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface)] public async Task ImplementRemainingExplicitlyMissingWhenAllImplemented() { diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs index 078a80c6c996b..1a328191c99b0 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs @@ -127,6 +127,7 @@ internal static async Task TestAddMethodAsync( modifiers, GetTypeSymbol(returnType)(context.SemanticModel), RefKind.None, + isInitOnly: false, explicitInterfaceImplementations, name, typeParameters, @@ -379,6 +380,7 @@ internal static async Task TestAddPropertyAsync( new Editing.DeclarationModifiers(isAbstract: getStatements == null), typeSymbol, RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, "get_" + name, typeParameters: default, @@ -390,6 +392,7 @@ internal static async Task TestAddPropertyAsync( new Editing.DeclarationModifiers(isAbstract: setStatements == null), GetTypeSymbol(typeof(void))(context.SemanticModel), RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, "set_" + name, typeParameters: default, diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs index c4bba9a44689b..e1a9172c041d7 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs @@ -57,6 +57,30 @@ public class [|C|] }}"); } + [Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)] + public async Task TestInitOnlyProperty() + { + var metadataSource = @"public class C { public int Property { get; init; } } +namespace System.Runtime.CompilerServices +{ + public sealed class IsExternalInit { } +} +"; + var symbolName = "C"; + + await GenerateAndVerifySourceAsync(metadataSource, symbolName, LanguageNames.CSharp, languageVersion: "Preview", metadataLanguageVersion: "Preview", + expected: $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null +// {CodeAnalysisResources.InMemoryAssembly} +#endregion + +public class [|C|] +{{ + public C(); + + public int Property {{ get; init; }} +}}"); + } + [Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)] public async Task TestTupleWithNames() { diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/GenerateEventHandlerItem.vb b/src/EditorFeatures/VisualBasic/NavigationBar/GenerateEventHandlerItem.vb index 8e7771e1ef33f..2e54dc0859041 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/GenerateEventHandlerItem.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/GenerateEventHandlerItem.vb @@ -59,6 +59,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar modifiers:=New DeclarationModifiers(), returnType:=delegateInvokeMethod.ReturnType, refKind:=delegateInvokeMethod.RefKind, + isInitOnly:=False, explicitInterfaceImplementations:=Nothing, name:=methodName, typeParameters:=Nothing, diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/GenerateFinalizerItem.vb b/src/EditorFeatures/VisualBasic/NavigationBar/GenerateFinalizerItem.vb index 7f352495280ad..4e084f773d2b0 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/GenerateFinalizerItem.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/GenerateFinalizerItem.vb @@ -48,6 +48,7 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar modifiers:=New DeclarationModifiers(isOverride:=True), returnType:=compilation.GetSpecialType(SpecialType.System_Void), refKind:=RefKind.None, + isInitOnly:=False, explicitInterfaceImplementations:=Nothing, name:=WellKnownMemberNames.DestructorName, typeParameters:=Nothing, diff --git a/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs index 479f75cf78ce7..dc7f494d1a347 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs @@ -114,6 +114,7 @@ private static async Task UpdateDocumentAsync( modifiers: new DeclarationModifiers(isStatic, isAsync: declaredSymbol.IsAsync), returnType: declaredSymbol.ReturnType, refKind: default, + isInitOnly: false, explicitInterfaceImplementations: default, name: methodName, typeParameters: typeParameters.ToImmutableArray(), diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs index 47ec985340ca8..ef4eb9c74962d 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs @@ -108,6 +108,7 @@ protected override OperationStatus GenerateMethodDefinition(bool modifiers: CreateMethodModifiers(), returnType: AnalyzerResult.ReturnType, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: _methodName.ToString(), typeParameters: CreateMethodTypeParameters(), diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs index 8e8f5e47c12c5..9fe63da7d06a8 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs @@ -213,6 +213,7 @@ private static IMethodSymbol GenerateMethodSymbol( modifiers: default, returnType: typeToGenerateIn, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: null, typeParameters: ImmutableArray.Empty, diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs index 83bc9b89e53f5..1dae7621da4a5 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs @@ -71,6 +71,7 @@ protected override async Task GenerateMemberAsync(ISymbol member, IName modifiers: MemberInsertionCompletionItem.GetModifiers(item), returnType: semanticModel.Compilation.GetSpecialType(SpecialType.System_Void), refKind: method.RefKind, + isInitOnly: false, explicitInterfaceImplementations: default, name: member.Name, typeParameters: method.TypeParameters, diff --git a/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs index d1bbda2ba72bf..e7a0366f2db21 100644 --- a/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs @@ -368,7 +368,7 @@ private static string GetLegalName(string name, Document document) private static IMethodSymbol CreateAccessorSymbol(IPropertySymbol prop, MethodKind kind) => CodeGenerationSymbolFactory.CreateMethodSymbol( attributes: default, Accessibility.Public, DeclarationModifiers.Abstract, - prop.Type, refKind: default, explicitInterfaceImplementations: default, + prop.Type, refKind: default, isInitOnly: false, explicitInterfaceImplementations: default, name: "", typeParameters: default, parameters: default, methodKind: kind); private static IMethodSymbol CreateConstructor( diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs index a0d5d8c7b370f..78493bb52385f 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs @@ -748,6 +748,7 @@ private static IMethodSymbol GenerateDeconstructMethod( modifiers: default, model.Compilation.GetSpecialType(SpecialType.System_Void), RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, WellKnownMemberNames.DeconstructMethodName, typeParameters: default, diff --git a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs index e087b0d2d0e8e..a48d11b59baed 100644 --- a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs +++ b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs @@ -469,6 +469,7 @@ private ImmutableArray CreateInterfaceMembers(IEnumerable incl modifiers: new DeclarationModifiers(isAbstract: true, isUnsafe: method.RequiresUnsafeModifier()), returnType: method.ReturnType, refKind: method.RefKind, + isInitOnly: method.IsInitOnly, explicitInterfaceImplementations: default, name: method.Name, typeParameters: method.TypeParameters, diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs index 818073e60a9a7..827716028923b 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs @@ -134,6 +134,7 @@ private IMethodSymbol CreateGetHashCodeMethod( modifiers: new DeclarationModifiers(isOverride: true), returnType: compilation.GetSpecialType(SpecialType.System_Int32), refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: GetHashCodeName, typeParameters: default, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs index 46b3031417b11..1c2ed75a7312b 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs @@ -73,6 +73,7 @@ private async Task TryInitializeMethodAsync( modifiers: default, returnType: semanticModel.Compilation.GetSpecialType(SpecialType.System_Void), refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: null, typeParameters: default, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs index bf54f7145e637..1c066ec2d6867 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs @@ -223,6 +223,7 @@ private static IMethodSymbol CreateMethodSymbolWithReturnType( modifiers: default, returnType: expressionType, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: null, typeParameters: ImmutableArray.Empty, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs index 9c37f18865eed..7d2b5faaed176 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs @@ -110,6 +110,7 @@ public async ValueTask GenerateMethodAsync( modifiers: new DeclarationModifiers(isStatic: State.IsStatic, isAbstract: isAbstract, isUnsafe: isUnsafe), returnType: returnType, refKind: DetermineRefKind(cancellationToken), + isInitOnly: false, explicitInterfaceImplementations: default, name: State.IdentifierToken.ValueText, typeParameters: DetermineTypeParameters(cancellationToken), diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs index b989a83c6495c..41c3837780f12 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs @@ -28,7 +28,7 @@ public WrappedMethodSymbol(IMethodSymbol methodSymbol, bool canImplementImplicit public IMethodSymbol ConstructedFrom => _symbol.ConstructedFrom; public bool IsReadOnly => _symbol.IsReadOnly; - public bool IsInitOnly => _symbol.IsInitOnly; // TODO2: test MetadataAsSource + public bool IsInitOnly => _symbol.IsInitOnly; public ImmutableArray ExplicitInterfaceImplementations { diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb index df945c3fc4920..3beececf3a6dc 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb @@ -69,6 +69,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod modifiers:=CreateMethodModifiers(), returnType:=Me.AnalyzerResult.ReturnType, refKind:=RefKind.None, + isInitOnly:=False, explicitInterfaceImplementations:=Nothing, name:=_methodName.ToString(), typeParameters:=CreateMethodTypeParameters(), diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb b/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb index 7a6c06fecf687..75e132993e10a 100644 --- a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb +++ b/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb @@ -150,6 +150,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod modifiers:=Nothing, returnType:=typeToGenerateIn, refKind:=RefKind.None, + isInitOnly:=False, explicitInterfaceImplementations:=Nothing, name:=Nothing, typeParameters:=ImmutableArray(Of ITypeParameterSymbol).Empty, diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs index b5cf1adf649ce..c06cb55200feb 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs @@ -258,10 +258,11 @@ private static AccessorListSyntax GenerateAccessorList( IPropertySymbol property, CodeGenerationDestination destination, Workspace workspace, CodeGenerationOptions options, ParseOptions parseOptions) { + var setAccessorKind = property.SetMethod?.IsInitOnly == true ? SyntaxKind.InitAccessorDeclaration : SyntaxKind.SetAccessorDeclaration; var accessors = new List { GenerateAccessorDeclaration(property, property.GetMethod, SyntaxKind.GetAccessorDeclaration, destination, workspace, options, parseOptions), - GenerateAccessorDeclaration(property, property.SetMethod, SyntaxKind.SetAccessorDeclaration, destination, workspace, options, parseOptions), + GenerateAccessorDeclaration(property, property.SetMethod, setAccessorKind, destination, workspace, options, parseOptions), }; return accessors[0] == null && accessors[1] == null diff --git a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs index fc45d5693f829..307aac7fade47 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs @@ -148,6 +148,7 @@ internal static IMethodSymbol CreateMethodSymbol( Accessibility accessibility, DeclarationModifiers modifiers, ITypeSymbol returnType, RefKind refKind, + bool isInitOnly, ImmutableArray explicitInterfaceImplementations, string name, ImmutableArray typeParameters, ImmutableArray parameters, @@ -156,8 +157,7 @@ internal static IMethodSymbol CreateMethodSymbol( ImmutableArray returnTypeAttributes = default, MethodKind methodKind = MethodKind.Ordinary) { - // TODO2 - var result = new CodeGenerationMethodSymbol(containingType, attributes, accessibility, modifiers, returnType, refKind, isInitOnly: false, explicitInterfaceImplementations, name, typeParameters, parameters, returnTypeAttributes, methodKind); + var result = new CodeGenerationMethodSymbol(containingType, attributes, accessibility, modifiers, returnType, refKind, isInitOnly, explicitInterfaceImplementations, name, typeParameters, parameters, returnTypeAttributes, methodKind); CodeGenerationMethodInfo.Attach(result, modifiers.IsNew, modifiers.IsUnsafe, modifiers.IsPartial, modifiers.IsAsync, statements, handlesExpressions); return result; } @@ -169,6 +169,7 @@ public static IMethodSymbol CreateMethodSymbol( ImmutableArray attributes, Accessibility accessibility, DeclarationModifiers modifiers, ITypeSymbol returnType, RefKind refKind, + bool isInitOnly, ImmutableArray explicitInterfaceImplementations, string name, ImmutableArray typeParameters, ImmutableArray parameters, @@ -177,7 +178,7 @@ public static IMethodSymbol CreateMethodSymbol( ImmutableArray returnTypeAttributes = default, MethodKind methodKind = MethodKind.Ordinary) { - return CreateMethodSymbol(null, attributes, accessibility, modifiers, returnType, refKind, explicitInterfaceImplementations, name, typeParameters, parameters, statements, handlesExpressions, returnTypeAttributes, methodKind); + return CreateMethodSymbol(null, attributes, accessibility, modifiers, returnType, refKind, isInitOnly, explicitInterfaceImplementations, name, typeParameters, parameters, statements, handlesExpressions, returnTypeAttributes, methodKind); } /// @@ -325,12 +326,13 @@ internal static IMethodSymbol CreateAccessorSymbol( ImmutableArray explicitInterfaceImplementations = default, ImmutableArray statements = default) { - return CodeGenerationSymbolFactory.CreateMethodSymbol( + return CreateMethodSymbol( attributes, accessibility ?? accessor.DeclaredAccessibility, accessor.GetSymbolModifiers().WithIsAbstract(statements == null), accessor.ReturnType, accessor.RefKind, + isInitOnly: accessor.IsInitOnly, explicitInterfaceImplementations.IsDefault ? accessor.ExplicitInterfaceImplementations : explicitInterfaceImplementations, accessor.Name, accessor.TypeParameters, @@ -347,12 +349,13 @@ public static IMethodSymbol CreateAccessorSymbol( Accessibility accessibility, ImmutableArray statements) { - return CodeGenerationSymbolFactory.CreateMethodSymbol( + return CreateMethodSymbol( attributes, accessibility, new DeclarationModifiers(isAbstract: statements == null), returnType: null, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: string.Empty, typeParameters: default, @@ -416,6 +419,7 @@ public static CodeGenerationNamedTypeSymbol CreateDelegateTypeSymbol( modifiers: new DeclarationModifiers(), returnType: returnType, refKind: refKind, + isInitOnly: false, explicitInterfaceImplementations: default, name: "Invoke", typeParameters: default, @@ -468,6 +472,7 @@ internal static IMethodSymbol CreateMethodSymbol( modifiers ?? method.GetSymbolModifiers(), returnType ?? method.ReturnType, method.RefKind, + isInitOnly: method.IsInitOnly, explicitInterfaceImplementations, name ?? method.Name, method.TypeParameters, @@ -488,7 +493,7 @@ internal static IPropertySymbol CreatePropertySymbol( IMethodSymbol getMethod = null, IMethodSymbol setMethod = null) { - return CodeGenerationSymbolFactory.CreatePropertySymbol( + return CreatePropertySymbol( attributes, accessibility ?? property.DeclaredAccessibility, modifiers ?? property.GetSymbolModifiers(), @@ -512,7 +517,7 @@ internal static IEventSymbol CreateEventSymbol( IMethodSymbol addMethod = null, IMethodSymbol removeMethod = null) { - return CodeGenerationSymbolFactory.CreateEventSymbol( + return CreateEventSymbol( attributes, accessibility ?? @event.DeclaredAccessibility, modifiers ?? @event.GetSymbolModifiers(), diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs index b49e790417ff6..f5916d85def9f 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Immutable; +using System.Diagnostics; using Microsoft.CodeAnalysis.Editing; namespace Microsoft.CodeAnalysis.CodeGeneration @@ -34,7 +35,10 @@ public CodeGenerationMethodSymbol( { this.ReturnType = returnType; this.RefKind = refKind; - this.IsInitOnly = isInitOnly; + + Debug.Assert(!isInitOnly || methodKind == MethodKind.PropertySet); + this.IsInitOnly = methodKind == MethodKind.PropertySet && isInitOnly; + this.TypeParameters = typeParameters.NullToEmpty(); this.Parameters = parameters.NullToEmpty(); this.MethodKind = methodKind; diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs index 3373ba737577b..52042abc0a782 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs @@ -102,6 +102,7 @@ public static IMethodSymbol RenameTypeParameters(this IMethodSymbol method, Immu method.GetSymbolModifiers(), method.ReturnType.SubstituteTypes(mapping, typeGenerator), method.RefKind, + method.IsInitOnly, method.ExplicitInterfaceImplementations, method.Name, updatedTypeParameters, @@ -128,6 +129,7 @@ public static IMethodSymbol RenameParameters( method.GetSymbolModifiers(), method.ReturnType, method.RefKind, + method.IsInitOnly, method.ExplicitInterfaceImplementations, method.Name, method.TypeParameters, diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs index be76eb3b7cc6c..37682612dca17 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs @@ -40,6 +40,7 @@ public static IMethodSymbol CreateEqualsMethod(this Compilation compilation, Imm modifiers: new DeclarationModifiers(isOverride: true), returnType: compilation.GetSpecialType(SpecialType.System_Boolean), refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: EqualsName, typeParameters: default, From 0bfc351a0e912bfb2f14426ac2671e6200ba6efb Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Fri, 8 May 2020 08:51:58 -0700 Subject: [PATCH 3/9] tweak --- .../Semantic/Semantics/InitOnlyMemberTests.cs | 100 ++++++++++++++++-- .../ImplementInterfaceTests.cs | 2 +- ...EventHookupCommandHandler_TabKeyCommand.cs | 1 + .../Venus/ContainedLanguageCodeSupport.cs | 1 + .../AbstractCodeModelObject_CodeGen.cs | 5 + .../CodeGenerationSymbolFactory.cs | 6 +- 6 files changed, 106 insertions(+), 9 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs index bbe8db601f0b8..a0826d1bebcc9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs @@ -19,11 +19,6 @@ public class InitOnlyMemberTests : CompilingTestBase // Spec: https://github.com/dotnet/csharplang/blob/master/proposals/init.md // PROTOTYPE(init-only): test allowed from 'with' expression - // PROTOTYPE(init-only): public API, confirm behavior of IsInitOnly and test on each leaf type of wrapped symbol - - // PROTOTYPE(init-only): open issues: - // PROTOTYPE(init-only): queue discussion on init methods (`init void Init()`) and collection initializers (`init void Add()`) - // PROTOTYPE(init-only): test dynamic scenario // PROTOTYPE(init-only): test whether reflection use property despite modreq? // PROTOTYPE(init-only): test behavior of old compiler with modreq. For example VB @@ -603,6 +598,74 @@ public string RegularProperty2 Assert.True(property.GetPublicSymbol().SetMethod.IsInitOnly); } + [Fact(Skip = "PROTOTYPE(init-only) Not yet supported")] + public void InitOnlyPropertyAssignmentAllowedInWithInitializer() + { + string source = @" +public class C +{ + public int Property { get; init; } + + void M(C c) + { + _ = c with { Property = null }; + } + + public C Clone() => throw null; +} + +class Derived : C +{ +} + +class Derived2 : Derived +{ + void M(C c) + { + _ = c with { Property = null }; + _ = this with { Property = null }; + } +} + +class Other +{ + void M() + { + var c = new C() with { Property = 42 }; + System.Console.Write($""{c.Property}""); + } +} +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + } + + [Fact(Skip = "PROTOTYPE(init-only) Not yet supported")] + public void InitOnlyPropertyAssignmentAllowedInWithInitializer_Evaluation() + { + string source = @" +public class C +{ + private int field; + public int Property { get { return field; } init { field = value; System.Console.Write(""set ""); } } + + public C Clone() { System.Console.Write(""clone ""); return this; } +} + +class Other +{ + public static void Main() + { + var c = new C() with { Property = 42 }; + System.Console.Write($""{c.Property}""); + } +} +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview, options: TestOptions.DebugExe); + comp.VerifyDiagnostics(); + CompileAndVerify(comp, expectedOutput: "clone set 42"); + } + [Fact] public void EvaluationInitOnlySetter() { @@ -2025,7 +2088,7 @@ public event System.Action Event } [Fact] - public void ConstructorsAreNotInitOnly() + public void ConstructorAndDestructorAreNotInitOnly() { string source = @" public class C @@ -2046,6 +2109,31 @@ public C() { } Assert.False(destructor.GetPublicSymbol().IsInitOnly); } + [Fact] + public void ConstructedMethodsAreNotInitOnly() + { + string source = @" +public class C +{ + void M() + { + M(); + } +} +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + + var tree = comp.SyntaxTrees[0]; + var root = tree.GetCompilationUnitRoot(); + var model = comp.GetSemanticModel(tree, ignoreAccessibility: true); + + var invocation = root.DescendantNodes().OfType().Single(); + var method = (IMethodSymbol)model.GetSymbolInfo(invocation).Symbol; + Assert.Equal("void C.M()", method.ToTestDisplayString()); + Assert.False(method.IsInitOnly); + } + [Fact] public void InitOnlyOnMembersOfRecords() { diff --git a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs index f624ba96b474c..d20c5f7ffc73b 100644 --- a/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/ImplementInterface/ImplementInterfaceTests.cs @@ -8437,7 +8437,7 @@ interface I class C : [|I|] { - public int Property { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public int Property { get => throw new System.NotImplementedException(); init => throw new System.NotImplementedException(); } }"); } diff --git a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index effd54bfad77b..13ead66e7d15c 100644 --- a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -265,6 +265,7 @@ private IMethodSymbol GetMethodSymbol( modifiers: new DeclarationModifiers(isStatic: eventHookupExpression.IsInStaticContext()), returnType: delegateInvokeMethod.ReturnType, refKind: delegateInvokeMethod.RefKind, + isInitOnly: false, explicitInterfaceImplementations: default, name: eventHandlerMethodName, typeParameters: default, diff --git a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs index 0e775f3145a9c..094a5479462a4 100644 --- a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs +++ b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs @@ -189,6 +189,7 @@ public static Tuple EnsureEventHandler( modifiers: new DeclarationModifiers(), returnType: targetDocument.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken).GetSpecialType(SpecialType.System_Void), refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: eventHandlerName, typeParameters: default, diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs index 85c11c2420c11..7a57c6f9568f8 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs @@ -85,6 +85,7 @@ protected SyntaxNode CreateEventDeclaration(SyntaxNode containerNode, string nam modifiers: new DeclarationModifiers(), returnType: null, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: "add_" + name, typeParameters: default, @@ -96,6 +97,7 @@ protected SyntaxNode CreateEventDeclaration(SyntaxNode containerNode, string nam modifiers: new DeclarationModifiers(), returnType: null, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: "remove_" + name, typeParameters: default, @@ -143,6 +145,7 @@ protected SyntaxNode CreateMethodDeclaration(SyntaxNode containerNode, string na modifiers: new DeclarationModifiers(), returnType: returnType, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: name, typeParameters: default, @@ -174,6 +177,7 @@ protected SyntaxNode CreatePropertyDeclaration(SyntaxNode containerNode, string modifiers: new DeclarationModifiers(), returnType: null, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: "get_" + name, typeParameters: default, @@ -190,6 +194,7 @@ protected SyntaxNode CreatePropertyDeclaration(SyntaxNode containerNode, string modifiers: new DeclarationModifiers(), returnType: null, refKind: RefKind.None, + isInitOnly: false, explicitInterfaceImplementations: default, name: "set_" + name, typeParameters: default, diff --git a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs index 307aac7fade47..6cfd347e13459 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs @@ -338,7 +338,8 @@ internal static IMethodSymbol CreateAccessorSymbol( accessor.TypeParameters, accessor.Parameters, statements, - returnTypeAttributes: accessor.GetReturnTypeAttributes()); + returnTypeAttributes: accessor.GetReturnTypeAttributes(), + methodKind: accessor.MethodKind); } /// @@ -478,7 +479,8 @@ internal static IMethodSymbol CreateMethodSymbol( method.TypeParameters, parameters ?? method.Parameters, statements, - returnTypeAttributes: returnTypeAttributes.HasValue ? returnTypeAttributes.Value : method.GetReturnTypeAttributes()); + returnTypeAttributes: returnTypeAttributes.HasValue ? returnTypeAttributes.Value : method.GetReturnTypeAttributes(), + methodKind: method.MethodKind); } internal static IPropertySymbol CreatePropertySymbol( From 1e59e42080557bcb4c7e384671776c2943430439 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Sun, 10 May 2020 07:17:11 -0700 Subject: [PATCH 4/9] Address feedback --- .../Semantic/Semantics/InitOnlyMemberTests.cs | 57 +++++++++++++++++++ .../Symbols/Retargeting/RetargetingTests.cs | 33 ----------- .../CodeGeneration/CodeGenerationTests.cs | 3 - .../NavigationBar/GenerateEventHandlerItem.vb | 1 - .../NavigationBar/GenerateFinalizerItem.vb | 1 - ...FunctionToMethodCodeRefactoringProvider.cs | 1 - ...harpMethodExtractor.CSharpCodeGenerator.cs | 1 - .../CSharpGenerateConversionService.cs | 1 - ...AbstractPartialMethodCompletionProvider.cs | 1 - ...ymousTypeToClassCodeRefactoringProvider.cs | 2 +- ...ertTupleToStructCodeRefactoringProvider.cs | 1 - .../AbstractExtractInterfaceService.cs | 4 +- ...ractGenerateEqualsAndGetHashCodeService.cs | 1 - ...tGenerateDeconstructMethodService.State.cs | 1 - .../AbstractGenerateMethodService.State.cs | 1 - ...arameterizedMemberService.SignatureInfo.cs | 1 - ...ethodExtractor.VisualBasicCodeGenerator.vb | 1 - .../VisualBasicGenerateConversionService.vb | 1 - ...EventHookupCommandHandler_TabKeyCommand.cs | 1 - .../Venus/ContainedLanguageCodeSupport.cs | 1 - .../AbstractCodeModelObject_CodeGen.cs | 5 -- .../CodeGenerationSymbolFactory.cs | 31 +++++----- .../CodeGenerationConstructorSymbol.cs | 1 - .../Symbols/CodeGenerationConversionSymbol.cs | 1 - .../Symbols/CodeGenerationDestructorSymbol.cs | 1 - .../Symbols/CodeGenerationMethodSymbol.cs | 8 +-- .../Symbols/CodeGenerationOperatorSymbol.cs | 1 - .../Extensions/IMethodSymbolExtensions.cs | 2 - ...xGeneratorExtensions_CreateEqualsMethod.cs | 1 - 29 files changed, 79 insertions(+), 86 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs index a0826d1bebcc9..bdd65da8895a3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs @@ -5,6 +5,7 @@ using System.Linq; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; +using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; @@ -2109,6 +2110,28 @@ public C() { } Assert.False(destructor.GetPublicSymbol().IsInitOnly); } + [Fact] + public void OperatorsAreNotInitOnly() + { + string source = @" +public class C +{ + public static implicit operator int(C c) => throw null; + public static bool operator +(C c1, C c2) => throw null; +} +"; + var comp = CreateCompilation(new[] { source, IsExternalInitTypeDefinition }, parseOptions: TestOptions.RegularPreview); + comp.VerifyDiagnostics(); + + var conversion = comp.GlobalNamespace.GetMember("C.op_Implicit"); + Assert.False(conversion.IsInitOnly); + Assert.False(conversion.GetPublicSymbol().IsInitOnly); + + var addition = comp.GlobalNamespace.GetMember("C.op_Addition"); + Assert.False(addition.IsInitOnly); + Assert.False(addition.GetPublicSymbol().IsInitOnly); + } + [Fact] public void ConstructedMethodsAreNotInitOnly() { @@ -3537,5 +3560,39 @@ void local() { } } } } + + [Fact] + public void RetargetProperties_WithInitOnlySetter() + { + // TODO2 + var source = +@"interface I +{ + object Property { get; init; } +}"; + var compilation = CreateCompilation(source); + + var sourceModule = compilation.SourceModule; + var sourceAssembly = (SourceAssemblySymbol)sourceModule.ContainingAssembly; + + var retargetingAssembly = new RetargetingAssemblySymbol(sourceAssembly, isLinked: false); + retargetingAssembly.SetCorLibrary(sourceAssembly.CorLibrary); + var retargetingModule = retargetingAssembly.Modules[0]; + var retargetingNamespace = retargetingModule.GlobalNamespace; + + var property = retargetingNamespace.GetMember("I.Property"); + MethodSymbol getMethod = property.GetMethod; + MethodSymbol setMethod = property.SetMethod; + + Assert.Equal("System.Object I.Property { get; init; }", property.ToTestDisplayString()); + Assert.Equal("void modreq(System.Runtime.CompilerServices.IsExternalInit[missing]) I.Property.init", + setMethod.ToTestDisplayString()); + + Assert.False(getMethod.IsInitOnly); + Assert.False(getMethod.GetPublicSymbol().IsInitOnly); + + Assert.True(setMethod.IsInitOnly); + Assert.True(setMethod.GetPublicSymbol().IsInitOnly); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs index d2a7795bfaacb..877f2d1f4b999 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs @@ -121,39 +121,6 @@ object this[I index] RetargetingSymbolChecker.CheckSymbols(sourceNamespace.GetMember("C"), retargetingNamespace.GetMember("C")); } - [Fact, CompilerTrait(CompilerFeature.InitOnlySetters)] - public void RetargetProperties_WithInitOnlySetter() - { - var source = -@"interface I -{ - object Property { get; init; } -}"; - var compilation = CreateCompilation(source); - - var sourceModule = compilation.SourceModule; - var sourceAssembly = (SourceAssemblySymbol)sourceModule.ContainingAssembly; - - var retargetingAssembly = new RetargetingAssemblySymbol(sourceAssembly, isLinked: false); - retargetingAssembly.SetCorLibrary(sourceAssembly.CorLibrary); - var retargetingModule = retargetingAssembly.Modules[0]; - var retargetingNamespace = retargetingModule.GlobalNamespace; - - var property = retargetingNamespace.GetMember("I.Property"); - MethodSymbol getMethod = property.GetMethod; - MethodSymbol setMethod = property.SetMethod; - - Assert.Equal("System.Object I.Property { get; init; }", property.ToTestDisplayString()); - Assert.Equal("void modreq(System.Runtime.CompilerServices.IsExternalInit[missing]) I.Property.init", - setMethod.ToTestDisplayString()); - - Assert.False(getMethod.IsInitOnly); - Assert.False(getMethod.GetPublicSymbol().IsInitOnly); - - Assert.True(setMethod.IsInitOnly); - Assert.True(setMethod.GetPublicSymbol().IsInitOnly); - } - [Fact] public void RetargetFields() { diff --git a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs index 1a328191c99b0..078a80c6c996b 100644 --- a/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs +++ b/src/EditorFeatures/Test/CodeGeneration/CodeGenerationTests.cs @@ -127,7 +127,6 @@ internal static async Task TestAddMethodAsync( modifiers, GetTypeSymbol(returnType)(context.SemanticModel), RefKind.None, - isInitOnly: false, explicitInterfaceImplementations, name, typeParameters, @@ -380,7 +379,6 @@ internal static async Task TestAddPropertyAsync( new Editing.DeclarationModifiers(isAbstract: getStatements == null), typeSymbol, RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, "get_" + name, typeParameters: default, @@ -392,7 +390,6 @@ internal static async Task TestAddPropertyAsync( new Editing.DeclarationModifiers(isAbstract: setStatements == null), GetTypeSymbol(typeof(void))(context.SemanticModel), RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, "set_" + name, typeParameters: default, diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/GenerateEventHandlerItem.vb b/src/EditorFeatures/VisualBasic/NavigationBar/GenerateEventHandlerItem.vb index 2e54dc0859041..8e7771e1ef33f 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/GenerateEventHandlerItem.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/GenerateEventHandlerItem.vb @@ -59,7 +59,6 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar modifiers:=New DeclarationModifiers(), returnType:=delegateInvokeMethod.ReturnType, refKind:=delegateInvokeMethod.RefKind, - isInitOnly:=False, explicitInterfaceImplementations:=Nothing, name:=methodName, typeParameters:=Nothing, diff --git a/src/EditorFeatures/VisualBasic/NavigationBar/GenerateFinalizerItem.vb b/src/EditorFeatures/VisualBasic/NavigationBar/GenerateFinalizerItem.vb index 4e084f773d2b0..7f352495280ad 100644 --- a/src/EditorFeatures/VisualBasic/NavigationBar/GenerateFinalizerItem.vb +++ b/src/EditorFeatures/VisualBasic/NavigationBar/GenerateFinalizerItem.vb @@ -48,7 +48,6 @@ Namespace Microsoft.CodeAnalysis.Editor.VisualBasic.NavigationBar modifiers:=New DeclarationModifiers(isOverride:=True), returnType:=compilation.GetSpecialType(SpecialType.System_Void), refKind:=RefKind.None, - isInitOnly:=False, explicitInterfaceImplementations:=Nothing, name:=WellKnownMemberNames.DestructorName, typeParameters:=Nothing, diff --git a/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs b/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs index dc7f494d1a347..479f75cf78ce7 100644 --- a/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs +++ b/src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs @@ -114,7 +114,6 @@ private static async Task UpdateDocumentAsync( modifiers: new DeclarationModifiers(isStatic, isAsync: declaredSymbol.IsAsync), returnType: declaredSymbol.ReturnType, refKind: default, - isInitOnly: false, explicitInterfaceImplementations: default, name: methodName, typeParameters: typeParameters.ToImmutableArray(), diff --git a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs index ef4eb9c74962d..47ec985340ca8 100644 --- a/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs +++ b/src/Features/CSharp/Portable/ExtractMethod/CSharpMethodExtractor.CSharpCodeGenerator.cs @@ -108,7 +108,6 @@ protected override OperationStatus GenerateMethodDefinition(bool modifiers: CreateMethodModifiers(), returnType: AnalyzerResult.ReturnType, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: _methodName.ToString(), typeParameters: CreateMethodTypeParameters(), diff --git a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs index 9fe63da7d06a8..8e8f5e47c12c5 100644 --- a/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs +++ b/src/Features/CSharp/Portable/GenerateMember/GenerateParameterizedMember/CSharpGenerateConversionService.cs @@ -213,7 +213,6 @@ private static IMethodSymbol GenerateMethodSymbol( modifiers: default, returnType: typeToGenerateIn, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: null, typeParameters: ImmutableArray.Empty, diff --git a/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs b/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs index 1dae7621da4a5..83bc9b89e53f5 100644 --- a/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs +++ b/src/Features/Core/Portable/Completion/Providers/AbstractPartialMethodCompletionProvider.cs @@ -71,7 +71,6 @@ protected override async Task GenerateMemberAsync(ISymbol member, IName modifiers: MemberInsertionCompletionItem.GetModifiers(item), returnType: semanticModel.Compilation.GetSpecialType(SpecialType.System_Void), refKind: method.RefKind, - isInitOnly: false, explicitInterfaceImplementations: default, name: member.Name, typeParameters: method.TypeParameters, diff --git a/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs index e7a0366f2db21..d1bbda2ba72bf 100644 --- a/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertAnonymousTypeToClass/AbstractConvertAnonymousTypeToClassCodeRefactoringProvider.cs @@ -368,7 +368,7 @@ private static string GetLegalName(string name, Document document) private static IMethodSymbol CreateAccessorSymbol(IPropertySymbol prop, MethodKind kind) => CodeGenerationSymbolFactory.CreateMethodSymbol( attributes: default, Accessibility.Public, DeclarationModifiers.Abstract, - prop.Type, refKind: default, isInitOnly: false, explicitInterfaceImplementations: default, + prop.Type, refKind: default, explicitInterfaceImplementations: default, name: "", typeParameters: default, parameters: default, methodKind: kind); private static IMethodSymbol CreateConstructor( diff --git a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs index 78493bb52385f..a0d5d8c7b370f 100644 --- a/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs +++ b/src/Features/Core/Portable/ConvertTupleToStruct/AbstractConvertTupleToStructCodeRefactoringProvider.cs @@ -748,7 +748,6 @@ private static IMethodSymbol GenerateDeconstructMethod( modifiers: default, model.Compilation.GetSpecialType(SpecialType.System_Void), RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, WellKnownMemberNames.DeconstructMethodName, typeParameters: default, diff --git a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs index a48d11b59baed..2ae30acc5d1da 100644 --- a/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs +++ b/src/Features/Core/Portable/ExtractInterface/AbstractExtractInterfaceService.cs @@ -469,11 +469,11 @@ private ImmutableArray CreateInterfaceMembers(IEnumerable incl modifiers: new DeclarationModifiers(isAbstract: true, isUnsafe: method.RequiresUnsafeModifier()), returnType: method.ReturnType, refKind: method.RefKind, - isInitOnly: method.IsInitOnly, explicitInterfaceImplementations: default, name: method.Name, typeParameters: method.TypeParameters, - parameters: method.Parameters)); + parameters: method.Parameters, + isInitOnly: method.IsInitOnly)); break; case SymbolKind.Property: var property = member as IPropertySymbol; diff --git a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs index 827716028923b..818073e60a9a7 100644 --- a/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs +++ b/src/Features/Core/Portable/GenerateEqualsAndGetHashCodeFromMembers/AbstractGenerateEqualsAndGetHashCodeService.cs @@ -134,7 +134,6 @@ private IMethodSymbol CreateGetHashCodeMethod( modifiers: new DeclarationModifiers(isOverride: true), returnType: compilation.GetSpecialType(SpecialType.System_Int32), refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: GetHashCodeName, typeParameters: default, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs index 1c2ed75a7312b..46b3031417b11 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateDeconstructMethodService.State.cs @@ -73,7 +73,6 @@ private async Task TryInitializeMethodAsync( modifiers: default, returnType: semanticModel.Compilation.GetSpecialType(SpecialType.System_Void), refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: null, typeParameters: default, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs index 1c066ec2d6867..bf54f7145e637 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateMethodService.State.cs @@ -223,7 +223,6 @@ private static IMethodSymbol CreateMethodSymbolWithReturnType( modifiers: default, returnType: expressionType, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: null, typeParameters: ImmutableArray.Empty, diff --git a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs index 7d2b5faaed176..9c37f18865eed 100644 --- a/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs +++ b/src/Features/Core/Portable/GenerateMember/GenerateParameterizedMember/AbstractGenerateParameterizedMemberService.SignatureInfo.cs @@ -110,7 +110,6 @@ public async ValueTask GenerateMethodAsync( modifiers: new DeclarationModifiers(isStatic: State.IsStatic, isAbstract: isAbstract, isUnsafe: isUnsafe), returnType: returnType, refKind: DetermineRefKind(cancellationToken), - isInitOnly: false, explicitInterfaceImplementations: default, name: State.IdentifierToken.ValueText, typeParameters: DetermineTypeParameters(cancellationToken), diff --git a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb index 3beececf3a6dc..df945c3fc4920 100644 --- a/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb +++ b/src/Features/VisualBasic/Portable/ExtractMethod/VisualBasicMethodExtractor.VisualBasicCodeGenerator.vb @@ -69,7 +69,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExtractMethod modifiers:=CreateMethodModifiers(), returnType:=Me.AnalyzerResult.ReturnType, refKind:=RefKind.None, - isInitOnly:=False, explicitInterfaceImplementations:=Nothing, name:=_methodName.ToString(), typeParameters:=CreateMethodTypeParameters(), diff --git a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb b/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb index 75e132993e10a..7a6c06fecf687 100644 --- a/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb +++ b/src/Features/VisualBasic/Portable/GenerateMember/GenerateParameterizedMember/VisualBasicGenerateConversionService.vb @@ -150,7 +150,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.GenerateMember.GenerateMethod modifiers:=Nothing, returnType:=typeToGenerateIn, refKind:=RefKind.None, - isInitOnly:=False, explicitInterfaceImplementations:=Nothing, name:=Nothing, typeParameters:=ImmutableArray(Of ITypeParameterSymbol).Empty, diff --git a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs index 13ead66e7d15c..effd54bfad77b 100644 --- a/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs +++ b/src/VisualStudio/CSharp/Impl/EventHookup/EventHookupCommandHandler_TabKeyCommand.cs @@ -265,7 +265,6 @@ private IMethodSymbol GetMethodSymbol( modifiers: new DeclarationModifiers(isStatic: eventHookupExpression.IsInStaticContext()), returnType: delegateInvokeMethod.ReturnType, refKind: delegateInvokeMethod.RefKind, - isInitOnly: false, explicitInterfaceImplementations: default, name: eventHandlerMethodName, typeParameters: default, diff --git a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs index 094a5479462a4..0e775f3145a9c 100644 --- a/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs +++ b/src/VisualStudio/Core/Def/Implementation/Venus/ContainedLanguageCodeSupport.cs @@ -189,7 +189,6 @@ public static Tuple EnsureEventHandler( modifiers: new DeclarationModifiers(), returnType: targetDocument.Project.GetCompilationAsync(cancellationToken).WaitAndGetResult_Venus(cancellationToken).GetSpecialType(SpecialType.System_Void), refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: eventHandlerName, typeParameters: default, diff --git a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs index 7a57c6f9568f8..85c11c2420c11 100644 --- a/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs +++ b/src/VisualStudio/Core/Impl/CodeModel/AbstractCodeModelObject_CodeGen.cs @@ -85,7 +85,6 @@ protected SyntaxNode CreateEventDeclaration(SyntaxNode containerNode, string nam modifiers: new DeclarationModifiers(), returnType: null, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: "add_" + name, typeParameters: default, @@ -97,7 +96,6 @@ protected SyntaxNode CreateEventDeclaration(SyntaxNode containerNode, string nam modifiers: new DeclarationModifiers(), returnType: null, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: "remove_" + name, typeParameters: default, @@ -145,7 +143,6 @@ protected SyntaxNode CreateMethodDeclaration(SyntaxNode containerNode, string na modifiers: new DeclarationModifiers(), returnType: returnType, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: name, typeParameters: default, @@ -177,7 +174,6 @@ protected SyntaxNode CreatePropertyDeclaration(SyntaxNode containerNode, string modifiers: new DeclarationModifiers(), returnType: null, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: "get_" + name, typeParameters: default, @@ -194,7 +190,6 @@ protected SyntaxNode CreatePropertyDeclaration(SyntaxNode containerNode, string modifiers: new DeclarationModifiers(), returnType: null, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: "set_" + name, typeParameters: default, diff --git a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs index 6cfd347e13459..7a42fece9dd42 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs @@ -145,19 +145,21 @@ public static IMethodSymbol CreateDestructorSymbol( internal static IMethodSymbol CreateMethodSymbol( INamedTypeSymbol containingType, ImmutableArray attributes, - Accessibility accessibility, DeclarationModifiers modifiers, + Accessibility accessibility, + DeclarationModifiers modifiers, ITypeSymbol returnType, RefKind refKind, - bool isInitOnly, - ImmutableArray explicitInterfaceImplementations, string name, + ImmutableArray explicitInterfaceImplementations, + string name, ImmutableArray typeParameters, ImmutableArray parameters, ImmutableArray statements = default, ImmutableArray handlesExpressions = default, ImmutableArray returnTypeAttributes = default, - MethodKind methodKind = MethodKind.Ordinary) + MethodKind methodKind = MethodKind.Ordinary, + bool isInitOnly = false) { - var result = new CodeGenerationMethodSymbol(containingType, attributes, accessibility, modifiers, returnType, refKind, isInitOnly, explicitInterfaceImplementations, name, typeParameters, parameters, returnTypeAttributes, methodKind); + var result = new CodeGenerationMethodSymbol(containingType, attributes, accessibility, modifiers, returnType, refKind, explicitInterfaceImplementations, name, typeParameters, parameters, returnTypeAttributes, methodKind, isInitOnly); CodeGenerationMethodInfo.Attach(result, modifiers.IsNew, modifiers.IsUnsafe, modifiers.IsPartial, modifiers.IsAsync, statements, handlesExpressions); return result; } @@ -169,16 +171,16 @@ public static IMethodSymbol CreateMethodSymbol( ImmutableArray attributes, Accessibility accessibility, DeclarationModifiers modifiers, ITypeSymbol returnType, RefKind refKind, - bool isInitOnly, - ImmutableArray explicitInterfaceImplementations, string name, - ImmutableArray typeParameters, + ImmutableArray explicitInterfaceImplementations, + string name, ImmutableArray typeParameters, ImmutableArray parameters, ImmutableArray statements = default, ImmutableArray handlesExpressions = default, ImmutableArray returnTypeAttributes = default, - MethodKind methodKind = MethodKind.Ordinary) + MethodKind methodKind = MethodKind.Ordinary, + bool isInitOnly = false) { - return CreateMethodSymbol(null, attributes, accessibility, modifiers, returnType, refKind, isInitOnly, explicitInterfaceImplementations, name, typeParameters, parameters, statements, handlesExpressions, returnTypeAttributes, methodKind); + return CreateMethodSymbol(null, attributes, accessibility, modifiers, returnType, refKind, explicitInterfaceImplementations, name, typeParameters, parameters, statements, handlesExpressions, returnTypeAttributes, methodKind, isInitOnly); } /// @@ -332,14 +334,14 @@ internal static IMethodSymbol CreateAccessorSymbol( accessor.GetSymbolModifiers().WithIsAbstract(statements == null), accessor.ReturnType, accessor.RefKind, - isInitOnly: accessor.IsInitOnly, explicitInterfaceImplementations.IsDefault ? accessor.ExplicitInterfaceImplementations : explicitInterfaceImplementations, accessor.Name, accessor.TypeParameters, accessor.Parameters, - statements, + statements: statements, returnTypeAttributes: accessor.GetReturnTypeAttributes(), - methodKind: accessor.MethodKind); + methodKind: accessor.MethodKind, + isInitOnly: accessor.IsInitOnly); } /// @@ -356,7 +358,6 @@ public static IMethodSymbol CreateAccessorSymbol( new DeclarationModifiers(isAbstract: statements == null), returnType: null, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: string.Empty, typeParameters: default, @@ -420,7 +421,6 @@ public static CodeGenerationNamedTypeSymbol CreateDelegateTypeSymbol( modifiers: new DeclarationModifiers(), returnType: returnType, refKind: refKind, - isInitOnly: false, explicitInterfaceImplementations: default, name: "Invoke", typeParameters: default, @@ -473,7 +473,6 @@ internal static IMethodSymbol CreateMethodSymbol( modifiers ?? method.GetSymbolModifiers(), returnType ?? method.ReturnType, method.RefKind, - isInitOnly: method.IsInitOnly, explicitInterfaceImplementations, name ?? method.Name, method.TypeParameters, diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs index 73072289894c9..6b1ece917a28e 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructorSymbol.cs @@ -21,7 +21,6 @@ public CodeGenerationConstructorSymbol( modifiers, returnType: null, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: string.Empty, typeParameters: ImmutableArray.Empty, diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs index 588b01a667089..3cc466d22f548 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConversionSymbol.cs @@ -24,7 +24,6 @@ public CodeGenerationConversionSymbol( modifiers, returnType: toType, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: isImplicit ? WellKnownMemberNames.ImplicitConversionName : diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs index 8bc4bbeb66271..06c7e8dbf81ec 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationDestructorSymbol.cs @@ -17,7 +17,6 @@ public CodeGenerationDestructorSymbol( default, returnType: null, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: string.Empty, typeParameters: ImmutableArray.Empty, diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs index f5916d85def9f..0ff386bd5faf9 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs @@ -24,13 +24,13 @@ public CodeGenerationMethodSymbol( DeclarationModifiers modifiers, ITypeSymbol returnType, RefKind refKind, - bool isInitOnly, ImmutableArray explicitInterfaceImplementations, string name, ImmutableArray typeParameters, ImmutableArray parameters, ImmutableArray returnTypeAttributes, - MethodKind methodKind = MethodKind.Ordinary) + MethodKind methodKind = MethodKind.Ordinary, + bool isInitOnly = false) : base(containingType, attributes, declaredAccessibility, modifiers, name, returnTypeAttributes) { this.ReturnType = returnType; @@ -51,9 +51,9 @@ protected override CodeGenerationSymbol Clone() { var result = new CodeGenerationMethodSymbol(this.ContainingType, this.GetAttributes(), this.DeclaredAccessibility, this.Modifiers, - this.ReturnType, this.RefKind, this.IsInitOnly, this.ExplicitInterfaceImplementations, + this.ReturnType, this.RefKind, this.ExplicitInterfaceImplementations, this.Name, this.TypeParameters, this.Parameters, this.GetReturnTypeAttributes(), - this.MethodKind); + this.MethodKind, this.IsInitOnly); CodeGenerationMethodInfo.Attach(result, CodeGenerationMethodInfo.GetIsNew(this), diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs index 12ff7668b320e..c67847ce70190 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationOperatorSymbol.cs @@ -25,7 +25,6 @@ public CodeGenerationOperatorSymbol( modifiers, returnType: returnType, refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: GetMetadataName(operatorKind), typeParameters: ImmutableArray.Empty, diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs index 52042abc0a782..3373ba737577b 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/IMethodSymbolExtensions.cs @@ -102,7 +102,6 @@ public static IMethodSymbol RenameTypeParameters(this IMethodSymbol method, Immu method.GetSymbolModifiers(), method.ReturnType.SubstituteTypes(mapping, typeGenerator), method.RefKind, - method.IsInitOnly, method.ExplicitInterfaceImplementations, method.Name, updatedTypeParameters, @@ -129,7 +128,6 @@ public static IMethodSymbol RenameParameters( method.GetSymbolModifiers(), method.ReturnType, method.RefKind, - method.IsInitOnly, method.ExplicitInterfaceImplementations, method.Name, method.TypeParameters, diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs index 37682612dca17..be76eb3b7cc6c 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions_CreateEqualsMethod.cs @@ -40,7 +40,6 @@ public static IMethodSymbol CreateEqualsMethod(this Compilation compilation, Imm modifiers: new DeclarationModifiers(isOverride: true), returnType: compilation.GetSpecialType(SpecialType.System_Boolean), refKind: RefKind.None, - isInitOnly: false, explicitInterfaceImplementations: default, name: EqualsName, typeParameters: default, From 257307d28edc20c887c9d42b05653f616ab3ad17 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 11 May 2020 10:59:30 -0700 Subject: [PATCH 5/9] Use modern retargeting test --- .../Semantic/Semantics/InitOnlyMemberTests.cs | 58 +++++++++++-------- .../Symbols/Retargeting/RetargetingTests.cs | 1 - 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs index bdd65da8895a3..a60144dc49a74 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs @@ -3564,35 +3564,47 @@ void local() { } [Fact] public void RetargetProperties_WithInitOnlySetter() { - // TODO2 - var source = -@"interface I + var source0 = @" +public struct S { - object Property { get; init; } -}"; - var compilation = CreateCompilation(source); - - var sourceModule = compilation.SourceModule; - var sourceAssembly = (SourceAssemblySymbol)sourceModule.ContainingAssembly; + public int Property { get; init; } +} +"; - var retargetingAssembly = new RetargetingAssemblySymbol(sourceAssembly, isLinked: false); - retargetingAssembly.SetCorLibrary(sourceAssembly.CorLibrary); - var retargetingModule = retargetingAssembly.Modules[0]; - var retargetingNamespace = retargetingModule.GlobalNamespace; + var source1 = @" +class Program +{ + public static void Main() + { + var s = new S() { Property = 42 }; + System.Console.WriteLine(s.Property); + } +} +"; - var property = retargetingNamespace.GetMember("I.Property"); - MethodSymbol getMethod = property.GetMethod; - MethodSymbol setMethod = property.SetMethod; + var source2 = @" +class Program +{ + public static void Main() + { + var s = new S() { Property = 43 }; + System.Console.WriteLine(s.Property); + } +} +"; - Assert.Equal("System.Object I.Property { get; init; }", property.ToTestDisplayString()); - Assert.Equal("void modreq(System.Runtime.CompilerServices.IsExternalInit[missing]) I.Property.init", - setMethod.ToTestDisplayString()); + var comp1 = CreateCompilation(new[] { source0, source1, IsExternalInitTypeDefinition }, + targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + CompileAndVerify(comp1, expectedOutput: "42"); + var comp1Ref = new[] { comp1.ToMetadataReference() }; - Assert.False(getMethod.IsInitOnly); - Assert.False(getMethod.GetPublicSymbol().IsInitOnly); + var comp7 = CreateCompilation(source2, references: comp1Ref, + targetFramework: TargetFramework.Mscorlib46, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); + CompileAndVerify(comp7, expectedOutput: "43"); - Assert.True(setMethod.IsInitOnly); - Assert.True(setMethod.GetPublicSymbol().IsInitOnly); + var property = comp7.GetMember("S.Property"); + var setter = (RetargetingMethodSymbol)property.SetMethod; + Assert.True(setter.IsInitOnly); } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs index 877f2d1f4b999..1544c145b3c63 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Retargeting/RetargetingTests.cs @@ -13,7 +13,6 @@ using Roslyn.Test.Utilities; using Xunit; using Utils = Microsoft.CodeAnalysis.CSharp.UnitTests.CompilationUtils; -using Microsoft.CodeAnalysis.Test.Utilities; namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Retargeting { From 5db0e22198765832a67bce7c5c8bac895da7de0b Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 11 May 2020 13:08:43 -0700 Subject: [PATCH 6/9] IDE tweak --- .../Portable/CodeGeneration/CodeGenerationSymbolFactory.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs index 7a42fece9dd42..97d55d49181c2 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/CodeGenerationSymbolFactory.cs @@ -479,7 +479,8 @@ internal static IMethodSymbol CreateMethodSymbol( parameters ?? method.Parameters, statements, returnTypeAttributes: returnTypeAttributes.HasValue ? returnTypeAttributes.Value : method.GetReturnTypeAttributes(), - methodKind: method.MethodKind); + methodKind: method.MethodKind, + isInitOnly: method.IsInitOnly); } internal static IPropertySymbol CreatePropertySymbol( From dc3bbd60c829127d3c1b619ce921fad8c19445ec Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 11 May 2020 14:02:33 -0700 Subject: [PATCH 7/9] Tweak doc comment --- src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs index 16b5d4c0694d1..4c504ba318843 100644 --- a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs @@ -141,8 +141,7 @@ public interface IMethodSymbol : ISymbol bool IsReadOnly { get; } /// - /// 'init' set accessors can only be invoked during construction or in the initialization phase - /// that follows construction. + /// Returns true for 'init' set accessors, and false otherwise. /// bool IsInitOnly { get; } From 63d368a8b81991989d7d2e1ee76d4afc4d1b6a98 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Mon, 11 May 2020 15:05:06 -0700 Subject: [PATCH 8/9] Fix incorrect cast in test --- .../CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs index a60144dc49a74..b6e0f3565b737 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs @@ -2127,7 +2127,7 @@ public class C Assert.False(conversion.IsInitOnly); Assert.False(conversion.GetPublicSymbol().IsInitOnly); - var addition = comp.GlobalNamespace.GetMember("C.op_Addition"); + var addition = comp.GlobalNamespace.GetMember("C.op_Addition"); Assert.False(addition.IsInitOnly); Assert.False(addition.GetPublicSymbol().IsInitOnly); } From 307e0916d7c23f13d763a4b2f59c896d9e3d7083 Mon Sep 17 00:00:00 2001 From: Julien Couvreur Date: Tue, 12 May 2020 07:44:32 -0700 Subject: [PATCH 9/9] Fixup PE verification for retargeting test --- .../CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs index b6e0f3565b737..3242301f091d3 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/InitOnlyMemberTests.cs @@ -3595,7 +3595,9 @@ public static void Main() var comp1 = CreateCompilation(new[] { source0, source1, IsExternalInitTypeDefinition }, targetFramework: TargetFramework.Mscorlib40, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview); - CompileAndVerify(comp1, expectedOutput: "42"); + // PEVerify: [ : S::set_Property] Cannot change initonly field outside its .ctor. + CompileAndVerify(comp1, expectedOutput: "42", + verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Fails); var comp1Ref = new[] { comp1.ToMetadataReference() }; var comp7 = CreateCompilation(source2, references: comp1Ref,