From 2acb948d8b89688c7a7233094d99bbbf6d67828c Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 26 Mar 2019 14:44:38 -0700 Subject: [PATCH 01/12] Add IsDeclaredReadOnly and IsEffectivelyReadOnly to public API --- .../AnonymousType.SynthesizedMethodBase.cs | 2 +- .../Portable/Symbols/ErrorMethodSymbol.cs | 2 +- .../CSharp/Portable/Symbols/MethodSymbol.cs | 6 ++---- .../Symbols/ReducedExtensionMethodSymbol.cs | 2 +- .../Symbols/SignatureOnlyMethodSymbol.cs | 2 +- .../Portable/Symbols/Source/LambdaSymbol.cs | 2 +- .../Symbols/Source/LocalFunctionSymbol.cs | 2 +- .../Source/SourceMemberMethodSymbol.cs | 2 +- .../Source/SourcePropertyAccessorSymbol.cs | 2 +- .../SynthesizedEntryPointSymbol.cs | 2 +- .../SynthesizedGlobalMethodSymbol.cs | 2 +- .../SynthesizedInstanceMethodSymbol.cs | 2 +- .../SynthesizedIntrinsicOperatorSymbol.cs | 2 +- .../SynthesizedStaticConstructor.cs | 2 +- .../Symbols/Wrapped/WrappedMethodSymbol.cs | 2 +- .../Core/Portable/PublicAPI.Unshipped.txt | 2 ++ .../Core/Portable/Symbols/IMethodSymbol.cs | 13 +++++++++++++ .../Portable/Symbols/MethodSymbol.vb | 19 +++++++++++++++++++ ...dataAsSourceService.WrappedMethodSymbol.cs | 4 ++++ .../CodeGenerationAbstractMethodSymbol.cs | 2 ++ 20 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs index f6a7dead0898b..4154e4633f6a4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs @@ -117,7 +117,7 @@ public sealed override ImmutableArray ExplicitInterfaceImplementat get { return ImmutableArray.Empty; } } - internal sealed override bool IsDeclaredReadOnly => true; + public sealed override bool IsDeclaredReadOnly => true; public sealed override ImmutableArray RefCustomModifiers { diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs index d6b3ff565fa9a..70aa04e8c0cb6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs @@ -124,7 +124,7 @@ public override ImmutableArray ExplicitInterfaceImplementations get { return ImmutableArray.Empty; } } - internal override bool IsDeclaredReadOnly => false; + public override bool IsDeclaredReadOnly => false; internal override int ParameterCount { diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index a7667b4aed096..d78827b96179b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -302,20 +302,18 @@ internal virtual bool IsExplicitInterfaceImplementation get { return ExplicitInterfaceImplementations.Any(); } } - // PROTOTYPE: this should become public API /// /// Indicates whether the method is declared readonly, i.e. /// whether 'this' is readonly in the scope of the method. /// See also /// - internal abstract bool IsDeclaredReadOnly { get; } + public abstract bool IsDeclaredReadOnly { get; } - // PROTOTYPE: this should become public API /// /// Indicates whether the method is effectively readonly, /// by either the method or the containing type being marked readonly. /// - internal bool IsEffectivelyReadOnly => (IsDeclaredReadOnly || ContainingType?.IsReadOnly == true) && IsValidReadOnlyTarget; + public bool IsEffectivelyReadOnly => (IsDeclaredReadOnly || ContainingType?.IsReadOnly == true) && IsValidReadOnlyTarget; protected bool IsValidReadOnlyTarget => !IsStatic && ContainingType.IsStructType() && MethodKind != MethodKind.Constructor; diff --git a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs index b53733ef2482e..a7e2e35f5226d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs @@ -374,7 +374,7 @@ internal override bool IsExplicitInterfaceImplementation } // extension methods are static and therefore not readonly - internal override bool IsDeclaredReadOnly => false; + public override bool IsDeclaredReadOnly => false; public override ImmutableArray ExplicitInterfaceImplementations { diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs index 0e434b6057de2..5ee97e9baa716 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs @@ -143,7 +143,7 @@ internal override bool IsMetadataFinal } } - internal override bool IsDeclaredReadOnly => false; + public override bool IsDeclaredReadOnly => false; internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index 20be8ee633640..e1d6da11aa7ed 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -396,7 +396,7 @@ internal override bool GenerateDebugInfo get { return true; } } - internal override bool IsDeclaredReadOnly => false; + public override bool IsDeclaredReadOnly => false; public override ImmutableArray GetTypeParameterConstraintClauses(bool early) => ImmutableArray.Empty; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index f4c5a243ce146..b3f0f5acc0f9c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -360,7 +360,7 @@ internal override TypeWithAnnotations IteratorElementTypeWithAnnotations internal bool IsExpressionBodied => _syntax.Body == null && _syntax.ExpressionBody != null; - internal override bool IsDeclaredReadOnly => false; + public override bool IsDeclaredReadOnly => false; public override DllImportData GetDllImportData() => null; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index 0a584f8e714fc..f5830e4c7a8bf 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -509,7 +509,7 @@ public sealed override bool IsAsync } } - internal override bool IsDeclaredReadOnly + public override bool IsDeclaredReadOnly { get { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index 1a38b3d4e3bbc..e3139348a6124 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -413,7 +413,7 @@ internal Accessibility LocalAccessibility /// /// Indicates whether this accessor is readonly due to reasons scoped to itself and its containing property. /// - internal override bool IsDeclaredReadOnly => LocalDeclaredReadOnly || _property.HasReadOnlyModifier || IsReadOnlyAutoGetter; + public override bool IsDeclaredReadOnly => LocalDeclaredReadOnly || _property.HasReadOnlyModifier || IsReadOnlyAutoGetter; private bool IsReadOnlyAutoGetter => ContainingType.IsStructType() && !_property.IsStatic && _isAutoPropertyAccessor && MethodKind == MethodKind.PropertyGet; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index a61353ef8c5c7..1557f20cfe96f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs @@ -210,7 +210,7 @@ public override ImmutableArray ExplicitInterfaceImplementations get { return ImmutableArray.Empty; } } - internal sealed override bool IsDeclaredReadOnly => false; + public sealed override bool IsDeclaredReadOnly => false; internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs index fad5243ebcd39..a322c8be08c90 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs @@ -300,7 +300,7 @@ public override ImmutableArray ExplicitInterfaceImplementations get { return ImmutableArray.Empty; } } - internal sealed override bool IsDeclaredReadOnly => false; + public sealed override bool IsDeclaredReadOnly => false; internal override bool SynthesizesLoweredBoundBody { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs index 89f515fcef776..46a24976dc56a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs @@ -57,6 +57,6 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l throw ExceptionUtilities.Unreachable; } - internal override bool IsDeclaredReadOnly => false; + public override bool IsDeclaredReadOnly => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index dea274abaf359..b5c1203997e3d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -261,7 +261,7 @@ public override ImmutableArray ExplicitInterfaceImplementations } } - internal override bool IsDeclaredReadOnly => true; + public override bool IsDeclaredReadOnly => true; public override ImmutableArray RefCustomModifiers { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs index 8aae979b67667..768cfc6aff315 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs @@ -278,7 +278,7 @@ public override ImmutableArray ExplicitInterfaceImplementations } } - internal override bool IsDeclaredReadOnly => false; + public override bool IsDeclaredReadOnly => false; public sealed override bool IsImplicitlyDeclared { diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs index ff4f6e08f44ad..099d449d8a5ce 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs @@ -321,6 +321,6 @@ internal override bool GenerateDebugInfo } } - internal override bool IsDeclaredReadOnly => UnderlyingMethod.IsDeclaredReadOnly; + public override bool IsDeclaredReadOnly => UnderlyingMethod.IsDeclaredReadOnly; } } diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 72eff0887f9aa..9454747f5d437 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,4 +1,6 @@ *REMOVED*Microsoft.CodeAnalysis.Operations.IEventAssignmentOperation.EventReference.get -> Microsoft.CodeAnalysis.Operations.IEventReferenceOperation +Microsoft.CodeAnalysis.IMethodSymbol.IsDeclaredReadOnly.get -> bool +Microsoft.CodeAnalysis.IMethodSymbol.IsEffectivelyReadOnly.get -> bool Microsoft.CodeAnalysis.Operations.IVariableDeclarationOperation.IgnoredDimensions.get -> System.Collections.Immutable.ImmutableArray abstract Microsoft.CodeAnalysis.Compilation.ClassifyCommonConversion(Microsoft.CodeAnalysis.ITypeSymbol source, Microsoft.CodeAnalysis.ITypeSymbol destination) -> Microsoft.CodeAnalysis.Operations.CommonConversion abstract Microsoft.CodeAnalysis.Compilation.ContainsSymbolsWithName(string name, Microsoft.CodeAnalysis.SymbolFilter filter = Microsoft.CodeAnalysis.SymbolFilter.TypeAndMember, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> bool diff --git a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs index 85043194a20cb..2da434fa6e9dc 100644 --- a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs @@ -117,6 +117,19 @@ public interface IMethodSymbol : ISymbol /// IMethodSymbol ConstructedFrom { get; } + /// + /// Indicates whether the method is declared readonly, i.e. + /// whether 'this' is readonly in the scope of the method. + /// See also + /// + bool IsDeclaredReadOnly { get; } + + /// + /// Indicates whether the method is effectively readonly, + /// by either the method or the containing type being marked readonly. + /// + bool IsEffectivelyReadOnly { 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 d27c72c44f527..758fb5f4b990f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb @@ -100,6 +100,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + + ''' + ''' Always returns false because the 'readonly members' feature is not available in VB. + ''' + Public ReadOnly Property IsDeclaredReadOnly As Boolean Implements IMethodSymbol.IsDeclaredReadOnly + Get + Return False + End Get + End Property + + ''' + ''' Always returns false because the 'readonly members' feature is not available in VB. + ''' + Public ReadOnly Property IsEffectivelyReadOnly As Boolean Implements IMethodSymbol.IsEffectivelyReadOnly + 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 13e54207aff59..437d1cf11cb20 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs @@ -25,6 +25,10 @@ public WrappedMethodSymbol(IMethodSymbol methodSymbol, bool canImplementImplicit public IMethodSymbol ConstructedFrom => _symbol.ConstructedFrom; + public bool IsDeclaredReadOnly => _symbol.IsDeclaredReadOnly; + + public bool IsEffectivelyReadOnly => _symbol.IsEffectivelyReadOnly; + public ImmutableArray ExplicitInterfaceImplementations { get diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs index c3936eece6ae6..28fbc6f9a86c9 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs @@ -39,6 +39,8 @@ protected CodeGenerationAbstractMethodSymbol( public abstract ImmutableArray TypeParameters { get; } public abstract ImmutableArray Parameters { get; } public abstract IMethodSymbol ConstructedFrom { get; } + public abstract bool IsDeclaredReadOnly { get; } + public abstract bool IsEffectivelyReadOnly { get; } public abstract IMethodSymbol OverriddenMethod { get; } public abstract IMethodSymbol ReducedFrom { get; } public abstract ITypeSymbol GetTypeInferredDuringReduction(ITypeParameterSymbol reducedFromTypeParameter); From a881856495de20369f930b523aeebad992563b42 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Wed, 27 Mar 2019 12:06:34 -0700 Subject: [PATCH 02/12] Fix build. Add simple SemanticModel test. --- .../Symbols/Metadata/PE/PEMethodSymbol.cs | 2 +- .../Semantics/ReadOnlyStructsTests.cs | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index b3bbeeee01ef7..970778bc942f2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -1040,7 +1040,7 @@ public override ImmutableArray ExplicitInterfaceImplementations } } - internal override bool IsDeclaredReadOnly + public override bool IsDeclaredReadOnly { get { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index 6c1c461694ec6..b0f5385675bae 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -1000,6 +1000,26 @@ public readonly int M() Assert.True(method.IsEffectivelyReadOnly); } + [Fact] + public void ReadOnlyMembers_SemanticModel() + { + var csharp = @" +public struct S1 +{ + public void M1() {} + public readonly void M2() {} +} +"; + Compilation comp = CreateCompilation(csharp); + var s1 = (INamedTypeSymbol)comp.GetSymbolsWithName("S1").Single(); + + Assert.False(((IMethodSymbol)s1.GetMembers("M1").Single()).IsDeclaredReadOnly); + Assert.False(((IMethodSymbol)s1.GetMembers("M1").Single()).IsEffectivelyReadOnly); + + Assert.True(((IMethodSymbol)s1.GetMembers("M2").Single()).IsDeclaredReadOnly); + Assert.True(((IMethodSymbol)s1.GetMembers("M2").Single()).IsEffectivelyReadOnly); + } + [Fact] public void ReadOnlyClass() { From fcba945ceb626c22933a16d6a306831c9a783c8e Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Wed, 27 Mar 2019 13:44:55 -0700 Subject: [PATCH 03/12] Fix Roslyn users of IMethodSymbol. Expand semantic model test. --- .../AnonymousType.SynthesizedMethodBase.cs | 2 +- .../SynthesizedIntrinsicOperatorSymbol.cs | 2 +- .../Semantics/ReadOnlyStructsTests.cs | 79 ++++++++++++++++++- .../Symbols/EEMethodSymbol.cs | 2 +- .../Symbols/PlaceholderMethodSymbol.cs | 2 +- .../CodeGenerationAbstractMethodSymbol.cs | 7 +- 6 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs index 4154e4633f6a4..d0d7591f67173 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs @@ -117,7 +117,7 @@ public sealed override ImmutableArray ExplicitInterfaceImplementat get { return ImmutableArray.Empty; } } - public sealed override bool IsDeclaredReadOnly => true; + public sealed override bool IsDeclaredReadOnly => false; public sealed override ImmutableArray RefCustomModifiers { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index b5c1203997e3d..3d3d532bfe6a8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -261,7 +261,7 @@ public override ImmutableArray ExplicitInterfaceImplementations } } - public override bool IsDeclaredReadOnly => true; + public override bool IsDeclaredReadOnly => false; public override ImmutableArray RefCustomModifiers { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index b0f5385675bae..0a5c0b3b91043 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -1004,20 +1004,91 @@ public readonly int M() public void ReadOnlyMembers_SemanticModel() { var csharp = @" +using System; + public struct S1 { public void M1() {} public readonly void M2() {} + + public int P1 { get; set; } + public readonly int P2 => 42; + public int P3 { readonly get => 123; } + public int P4 { readonly set {} } + public static int P5 { get; set; } + public readonly event Action E { add {} remove {} } +} + +public readonly struct S2 +{ + public void M1() {} + public int P1 { get; } + public int P2 => 42; + public int P3 { set {} } + public static int P4 { get; set; } + public event Action E { add {} remove {} } } "; Compilation comp = CreateCompilation(csharp); var s1 = (INamedTypeSymbol)comp.GetSymbolsWithName("S1").Single(); - Assert.False(((IMethodSymbol)s1.GetMembers("M1").Single()).IsDeclaredReadOnly); - Assert.False(((IMethodSymbol)s1.GetMembers("M1").Single()).IsEffectivelyReadOnly); + Assert.False(getMethod(s1, "M1").IsDeclaredReadOnly); + Assert.False(getMethod(s1, "M1").IsEffectivelyReadOnly); + + Assert.True(getMethod(s1, "M2").IsDeclaredReadOnly); + Assert.True(getMethod(s1, "M2").IsEffectivelyReadOnly); + + Assert.True(getProperty(s1, "P1").GetMethod.IsDeclaredReadOnly); + Assert.True(getProperty(s1, "P1").GetMethod.IsEffectivelyReadOnly); + Assert.False(getProperty(s1, "P1").SetMethod.IsDeclaredReadOnly); + Assert.False(getProperty(s1, "P1").SetMethod.IsEffectivelyReadOnly); + + Assert.True(getProperty(s1, "P2").GetMethod.IsDeclaredReadOnly); + Assert.True(getProperty(s1, "P2").GetMethod.IsEffectivelyReadOnly); + + Assert.True(getProperty(s1, "P3").GetMethod.IsDeclaredReadOnly); + Assert.True(getProperty(s1, "P3").GetMethod.IsEffectivelyReadOnly); + + Assert.True(getProperty(s1, "P4").SetMethod.IsDeclaredReadOnly); + Assert.True(getProperty(s1, "P4").SetMethod.IsEffectivelyReadOnly); + + Assert.False(getProperty(s1, "P5").GetMethod.IsDeclaredReadOnly); + Assert.False(getProperty(s1, "P5").GetMethod.IsEffectivelyReadOnly); + Assert.False(getProperty(s1, "P5").SetMethod.IsDeclaredReadOnly); + Assert.False(getProperty(s1, "P5").SetMethod.IsEffectivelyReadOnly); + + Assert.True(getEvent(s1, "E").AddMethod.IsDeclaredReadOnly); + Assert.True(getEvent(s1, "E").AddMethod.IsEffectivelyReadOnly); + + Assert.True(getEvent(s1, "E").RemoveMethod.IsDeclaredReadOnly); + Assert.True(getEvent(s1, "E").RemoveMethod.IsEffectivelyReadOnly); + + var s2 = comp.GetMember("S2"); + Assert.False(getMethod(s2, "M1").IsDeclaredReadOnly); + Assert.True(getMethod(s2, "M1").IsEffectivelyReadOnly); + + Assert.True(getProperty(s2, "P1").GetMethod.IsDeclaredReadOnly); + Assert.True(getProperty(s2, "P1").GetMethod.IsEffectivelyReadOnly); + + Assert.False(getProperty(s2, "P2").GetMethod.IsDeclaredReadOnly); + Assert.True(getProperty(s2, "P2").GetMethod.IsEffectivelyReadOnly); + + Assert.False(getProperty(s2, "P3").SetMethod.IsDeclaredReadOnly); + Assert.True(getProperty(s2, "P3").SetMethod.IsEffectivelyReadOnly); + + Assert.False(getProperty(s2, "P4").GetMethod.IsDeclaredReadOnly); + Assert.False(getProperty(s2, "P4").GetMethod.IsEffectivelyReadOnly); + Assert.False(getProperty(s2, "P4").SetMethod.IsDeclaredReadOnly); + Assert.False(getProperty(s2, "P4").SetMethod.IsEffectivelyReadOnly); + + Assert.False(getEvent(s2, "E").AddMethod.IsDeclaredReadOnly); + Assert.True(getEvent(s2, "E").AddMethod.IsEffectivelyReadOnly); + Assert.False(getEvent(s2, "E").RemoveMethod.IsDeclaredReadOnly); + Assert.True(getEvent(s2, "E").RemoveMethod.IsEffectivelyReadOnly); - Assert.True(((IMethodSymbol)s1.GetMembers("M2").Single()).IsDeclaredReadOnly); - Assert.True(((IMethodSymbol)s1.GetMembers("M2").Single()).IsEffectivelyReadOnly); + static IMethodSymbol getMethod(INamedTypeSymbol symbol, string name) => (IMethodSymbol)symbol.GetMembers(name).Single(); + static IPropertySymbol getProperty(INamedTypeSymbol symbol, string name) => (IPropertySymbol)symbol.GetMembers(name).Single(); + static IEventSymbol getEvent(INamedTypeSymbol symbol, string name) => (IEventSymbol)symbol.GetMembers(name).Single(); } [Fact] diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs index 8b156ac82f9f8..5ecf731072f02 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs @@ -405,7 +405,7 @@ public override bool IsExtern get { return false; } } - internal override bool IsDeclaredReadOnly => false; + public override bool IsDeclaredReadOnly => false; internal override ObsoleteAttributeData ObsoleteAttributeData { diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs index d9069d099bf1d..7e696b03f207b 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs @@ -118,7 +118,7 @@ public override bool IsVirtual get { return false; } } - internal override bool IsDeclaredReadOnly => false; + public override bool IsDeclaredReadOnly => false; public override ImmutableArray Locations { diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs index 28fbc6f9a86c9..b06147cfe6d85 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.Editing; @@ -39,8 +40,6 @@ protected CodeGenerationAbstractMethodSymbol( public abstract ImmutableArray TypeParameters { get; } public abstract ImmutableArray Parameters { get; } public abstract IMethodSymbol ConstructedFrom { get; } - public abstract bool IsDeclaredReadOnly { get; } - public abstract bool IsEffectivelyReadOnly { get; } public abstract IMethodSymbol OverriddenMethod { get; } public abstract IMethodSymbol ReducedFrom { get; } public abstract ITypeSymbol GetTypeInferredDuringReduction(ITypeParameterSymbol reducedFromTypeParameter); @@ -71,6 +70,10 @@ public override TResult Accept(SymbolVisitor visitor) public override SymbolKind Kind => SymbolKind.Method; + public virtual bool IsDeclaredReadOnly => throw new NotImplementedException(); + + public virtual bool IsEffectivelyReadOnly => throw new NotImplementedException(); + public virtual bool IsGenericMethod { get From b8aab4f292069e0963ebb64ca87af04c0d78fe93 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Wed, 27 Mar 2019 13:51:19 -0700 Subject: [PATCH 04/12] Fix visibility of MethodSymbol.vb members --- src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb index 758fb5f4b990f..cd2e19fe9791f 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb @@ -104,7 +104,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' ''' Always returns false because the 'readonly members' feature is not available in VB. ''' - Public ReadOnly Property IsDeclaredReadOnly As Boolean Implements IMethodSymbol.IsDeclaredReadOnly + Private ReadOnly Property IMethodSymbol_IsDeclaredReadOnly As Boolean Implements IMethodSymbol.IsDeclaredReadOnly Get Return False End Get @@ -113,7 +113,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' ''' Always returns false because the 'readonly members' feature is not available in VB. ''' - Public ReadOnly Property IsEffectivelyReadOnly As Boolean Implements IMethodSymbol.IsEffectivelyReadOnly + Private ReadOnly Property IMethodSymbol_IsEffectivelyReadOnly As Boolean Implements IMethodSymbol.IsEffectivelyReadOnly Get Return False End Get From 0855bb5f7fb62b7bf434aceb9a8059c91402e5dd Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Wed, 27 Mar 2019 15:26:07 -0700 Subject: [PATCH 05/12] Implement ReadOnly method API in CodeGenerationConstructedMethodSymbol --- .../Symbols/CodeGenerationAbstractMethodSymbol.cs | 6 ++---- .../Symbols/CodeGenerationConstructedMethodSymbol.cs | 4 ++++ .../CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs | 4 ++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs index b06147cfe6d85..5aa2fc03e47ce 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs @@ -40,6 +40,8 @@ protected CodeGenerationAbstractMethodSymbol( public abstract ImmutableArray TypeParameters { get; } public abstract ImmutableArray Parameters { get; } public abstract IMethodSymbol ConstructedFrom { get; } + public abstract bool IsDeclaredReadOnly { get; } + public abstract bool IsEffectivelyReadOnly { get; } public abstract IMethodSymbol OverriddenMethod { get; } public abstract IMethodSymbol ReducedFrom { get; } public abstract ITypeSymbol GetTypeInferredDuringReduction(ITypeParameterSymbol reducedFromTypeParameter); @@ -70,10 +72,6 @@ public override TResult Accept(SymbolVisitor visitor) public override SymbolKind Kind => SymbolKind.Method; - public virtual bool IsDeclaredReadOnly => throw new NotImplementedException(); - - public virtual bool IsEffectivelyReadOnly => throw new NotImplementedException(); - public virtual bool IsGenericMethod { get diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs index 28e10e143a3d9..b0e262ff9f88c 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs @@ -70,6 +70,10 @@ public override ImmutableArray Parameters public override IMethodSymbol ConstructedFrom => _constructedFrom; + public override bool IsDeclaredReadOnly => _constructedFrom.IsDeclaredReadOnly; + + public override bool IsEffectivelyReadOnly => _constructedFrom.IsEffectivelyReadOnly; + public override IMethodSymbol OverriddenMethod => // TODO(cyrusn): Construct this. _constructedFrom.OverriddenMethod; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs index 06fc76867d504..a6b1346f5f0df 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs @@ -85,6 +85,10 @@ public override ImmutableArray TypeArguments public override IMethodSymbol ConstructedFrom => this; + public override bool IsDeclaredReadOnly => throw new NotImplementedException(); + + public override bool IsEffectivelyReadOnly => throw new NotImplementedException(); + public override IMethodSymbol OverriddenMethod => null; public override IMethodSymbol ReducedFrom => null; From b765226eb816f5c323c28d952a4f2abcc0fde205 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Thu, 28 Mar 2019 12:24:10 -0700 Subject: [PATCH 06/12] Cleanup usings and change NotImplementedException to ExceptionUtilities.Unreachable --- .../Symbols/CodeGenerationAbstractMethodSymbol.cs | 2 -- .../CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs index 5aa2fc03e47ce..ede9b5126d753 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs @@ -1,7 +1,5 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; -using System.Collections.Generic; using System.Collections.Immutable; using Microsoft.CodeAnalysis.Editing; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs index a6b1346f5f0df..798ada261035d 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Immutable; using Microsoft.CodeAnalysis.Editing; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGeneration { @@ -85,9 +86,9 @@ public override ImmutableArray TypeArguments public override IMethodSymbol ConstructedFrom => this; - public override bool IsDeclaredReadOnly => throw new NotImplementedException(); + public override bool IsDeclaredReadOnly => throw ExceptionUtilities.Unreachable; - public override bool IsEffectivelyReadOnly => throw new NotImplementedException(); + public override bool IsEffectivelyReadOnly => throw ExceptionUtilities.Unreachable; public override IMethodSymbol OverriddenMethod => null; From be038dfc3480b5e926a90fdf00cc12a697ce1a11 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Mon, 1 Apr 2019 17:36:23 -0700 Subject: [PATCH 07/12] Simplify down to IMethodSymbol.IsReadOnly --- .../AnonymousType.SynthesizedMethodBase.cs | 2 +- .../Portable/Symbols/ErrorMethodSymbol.cs | 2 +- .../Symbols/Metadata/PE/PEMethodSymbol.cs | 2 +- .../CSharp/Portable/Symbols/MethodSymbol.cs | 12 +++- .../Symbols/ReducedExtensionMethodSymbol.cs | 2 +- .../Symbols/SignatureOnlyMethodSymbol.cs | 2 +- .../Portable/Symbols/Source/LambdaSymbol.cs | 2 +- .../Symbols/Source/LocalFunctionSymbol.cs | 2 +- .../Source/SourceMemberMethodSymbol.cs | 2 +- .../Source/SourcePropertyAccessorSymbol.cs | 2 +- .../SynthesizedEntryPointSymbol.cs | 2 +- .../SynthesizedGlobalMethodSymbol.cs | 2 +- .../SynthesizedInstanceMethodSymbol.cs | 2 +- .../SynthesizedIntrinsicOperatorSymbol.cs | 2 +- .../SynthesizedStaticConstructor.cs | 2 +- .../Symbols/Wrapped/WrappedMethodSymbol.cs | 2 +- .../Semantics/ReadOnlyStructsTests.cs | 57 +++++++------------ .../Core/Portable/PublicAPI.Unshipped.txt | 3 +- .../Core/Portable/Symbols/IMethodSymbol.cs | 13 +---- .../Portable/Symbols/MethodSymbol.vb | 12 +--- .../Symbols/EEMethodSymbol.cs | 2 +- .../Symbols/PlaceholderMethodSymbol.cs | 2 +- ...dataAsSourceService.WrappedMethodSymbol.cs | 4 +- .../CodeGenerationAbstractMethodSymbol.cs | 3 +- .../CodeGenerationConstructedMethodSymbol.cs | 4 +- .../Symbols/CodeGenerationMethodSymbol.cs | 4 +- 26 files changed, 55 insertions(+), 91 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs index d0d7591f67173..f6a7dead0898b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs @@ -117,7 +117,7 @@ public sealed override ImmutableArray ExplicitInterfaceImplementat get { return ImmutableArray.Empty; } } - public sealed override bool IsDeclaredReadOnly => false; + internal sealed override bool IsDeclaredReadOnly => true; public sealed override ImmutableArray RefCustomModifiers { diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs index 70aa04e8c0cb6..d6b3ff565fa9a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs @@ -124,7 +124,7 @@ public override ImmutableArray ExplicitInterfaceImplementations get { return ImmutableArray.Empty; } } - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => false; internal override int ParameterCount { diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index 970778bc942f2..b3bbeeee01ef7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -1040,7 +1040,7 @@ public override ImmutableArray ExplicitInterfaceImplementations } } - public override bool IsDeclaredReadOnly + internal override bool IsDeclaredReadOnly { get { diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index d78827b96179b..e40d673dce428 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -307,13 +307,13 @@ internal virtual bool IsExplicitInterfaceImplementation /// whether 'this' is readonly in the scope of the method. /// See also /// - public abstract bool IsDeclaredReadOnly { get; } + internal abstract bool IsDeclaredReadOnly { get; } /// /// Indicates whether the method is effectively readonly, /// by either the method or the containing type being marked readonly. /// - public bool IsEffectivelyReadOnly => (IsDeclaredReadOnly || ContainingType?.IsReadOnly == true) && IsValidReadOnlyTarget; + internal bool IsEffectivelyReadOnly => (IsDeclaredReadOnly || ContainingType?.IsReadOnly == true) && IsValidReadOnlyTarget; protected bool IsValidReadOnlyTarget => !IsStatic && ContainingType.IsStructType() && MethodKind != MethodKind.Constructor; @@ -1061,6 +1061,14 @@ IMethodSymbol IMethodSymbol.ConstructedFrom } } + bool IMethodSymbol.IsReadOnly + { + get + { + return this.IsEffectivelyReadOnly; + } + } + IMethodSymbol IMethodSymbol.OriginalDefinition { get diff --git a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs index a7e2e35f5226d..b53733ef2482e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs @@ -374,7 +374,7 @@ internal override bool IsExplicitInterfaceImplementation } // extension methods are static and therefore not readonly - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => false; public override ImmutableArray ExplicitInterfaceImplementations { diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs index 5ee97e9baa716..0e434b6057de2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs @@ -143,7 +143,7 @@ internal override bool IsMetadataFinal } } - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => false; internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) { throw ExceptionUtilities.Unreachable; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs index e1d6da11aa7ed..20be8ee633640 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LambdaSymbol.cs @@ -396,7 +396,7 @@ internal override bool GenerateDebugInfo get { return true; } } - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => false; public override ImmutableArray GetTypeParameterConstraintClauses(bool early) => ImmutableArray.Empty; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs index b3f0f5acc0f9c..f4c5a243ce146 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/LocalFunctionSymbol.cs @@ -360,7 +360,7 @@ internal override TypeWithAnnotations IteratorElementTypeWithAnnotations internal bool IsExpressionBodied => _syntax.Body == null && _syntax.ExpressionBody != null; - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => false; public override DllImportData GetDllImportData() => null; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index f5830e4c7a8bf..0a584f8e714fc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -509,7 +509,7 @@ public sealed override bool IsAsync } } - public override bool IsDeclaredReadOnly + internal override bool IsDeclaredReadOnly { get { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs index e3139348a6124..1a38b3d4e3bbc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs @@ -413,7 +413,7 @@ internal Accessibility LocalAccessibility /// /// Indicates whether this accessor is readonly due to reasons scoped to itself and its containing property. /// - public override bool IsDeclaredReadOnly => LocalDeclaredReadOnly || _property.HasReadOnlyModifier || IsReadOnlyAutoGetter; + internal override bool IsDeclaredReadOnly => LocalDeclaredReadOnly || _property.HasReadOnlyModifier || IsReadOnlyAutoGetter; private bool IsReadOnlyAutoGetter => ContainingType.IsStructType() && !_property.IsStatic && _isAutoPropertyAccessor && MethodKind == MethodKind.PropertyGet; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index 1557f20cfe96f..a61353ef8c5c7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs @@ -210,7 +210,7 @@ public override ImmutableArray ExplicitInterfaceImplementations get { return ImmutableArray.Empty; } } - public sealed override bool IsDeclaredReadOnly => false; + internal sealed override bool IsDeclaredReadOnly => false; internal sealed override bool IsMetadataNewSlot(bool ignoreInterfaceImplementationChanges = false) { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs index a322c8be08c90..fad5243ebcd39 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs @@ -300,7 +300,7 @@ public override ImmutableArray ExplicitInterfaceImplementations get { return ImmutableArray.Empty; } } - public sealed override bool IsDeclaredReadOnly => false; + internal sealed override bool IsDeclaredReadOnly => false; internal override bool SynthesizesLoweredBoundBody { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs index 46a24976dc56a..89f515fcef776 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceMethodSymbol.cs @@ -57,6 +57,6 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l throw ExceptionUtilities.Unreachable; } - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index 3d3d532bfe6a8..dea274abaf359 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -261,7 +261,7 @@ public override ImmutableArray ExplicitInterfaceImplementations } } - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => true; public override ImmutableArray RefCustomModifiers { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs index 768cfc6aff315..8aae979b67667 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs @@ -278,7 +278,7 @@ public override ImmutableArray ExplicitInterfaceImplementations } } - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => false; public sealed override bool IsImplicitlyDeclared { diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs index 099d449d8a5ce..ff4f6e08f44ad 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs @@ -321,6 +321,6 @@ internal override bool GenerateDebugInfo } } - public override bool IsDeclaredReadOnly => UnderlyingMethod.IsDeclaredReadOnly; + internal override bool IsDeclaredReadOnly => UnderlyingMethod.IsDeclaredReadOnly; } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index 0a5c0b3b91043..6b24223c3e801 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -1032,59 +1032,40 @@ public event Action E { add {} remove {} } Compilation comp = CreateCompilation(csharp); var s1 = (INamedTypeSymbol)comp.GetSymbolsWithName("S1").Single(); - Assert.False(getMethod(s1, "M1").IsDeclaredReadOnly); - Assert.False(getMethod(s1, "M1").IsEffectivelyReadOnly); + Assert.False(getMethod(s1, "M1").IsReadOnly); - Assert.True(getMethod(s1, "M2").IsDeclaredReadOnly); - Assert.True(getMethod(s1, "M2").IsEffectivelyReadOnly); + Assert.True(getMethod(s1, "M2").IsReadOnly); - Assert.True(getProperty(s1, "P1").GetMethod.IsDeclaredReadOnly); - Assert.True(getProperty(s1, "P1").GetMethod.IsEffectivelyReadOnly); - Assert.False(getProperty(s1, "P1").SetMethod.IsDeclaredReadOnly); - Assert.False(getProperty(s1, "P1").SetMethod.IsEffectivelyReadOnly); + Assert.True(getProperty(s1, "P1").GetMethod.IsReadOnly); + Assert.False(getProperty(s1, "P1").SetMethod.IsReadOnly); - Assert.True(getProperty(s1, "P2").GetMethod.IsDeclaredReadOnly); - Assert.True(getProperty(s1, "P2").GetMethod.IsEffectivelyReadOnly); + Assert.True(getProperty(s1, "P2").GetMethod.IsReadOnly); - Assert.True(getProperty(s1, "P3").GetMethod.IsDeclaredReadOnly); - Assert.True(getProperty(s1, "P3").GetMethod.IsEffectivelyReadOnly); + Assert.True(getProperty(s1, "P3").GetMethod.IsReadOnly); - Assert.True(getProperty(s1, "P4").SetMethod.IsDeclaredReadOnly); - Assert.True(getProperty(s1, "P4").SetMethod.IsEffectivelyReadOnly); + Assert.True(getProperty(s1, "P4").SetMethod.IsReadOnly); - Assert.False(getProperty(s1, "P5").GetMethod.IsDeclaredReadOnly); - Assert.False(getProperty(s1, "P5").GetMethod.IsEffectivelyReadOnly); - Assert.False(getProperty(s1, "P5").SetMethod.IsDeclaredReadOnly); - Assert.False(getProperty(s1, "P5").SetMethod.IsEffectivelyReadOnly); + Assert.False(getProperty(s1, "P5").GetMethod.IsReadOnly); + Assert.False(getProperty(s1, "P5").SetMethod.IsReadOnly); - Assert.True(getEvent(s1, "E").AddMethod.IsDeclaredReadOnly); - Assert.True(getEvent(s1, "E").AddMethod.IsEffectivelyReadOnly); + Assert.True(getEvent(s1, "E").AddMethod.IsReadOnly); - Assert.True(getEvent(s1, "E").RemoveMethod.IsDeclaredReadOnly); - Assert.True(getEvent(s1, "E").RemoveMethod.IsEffectivelyReadOnly); + Assert.True(getEvent(s1, "E").RemoveMethod.IsReadOnly); var s2 = comp.GetMember("S2"); - Assert.False(getMethod(s2, "M1").IsDeclaredReadOnly); - Assert.True(getMethod(s2, "M1").IsEffectivelyReadOnly); + Assert.True(getMethod(s2, "M1").IsReadOnly); - Assert.True(getProperty(s2, "P1").GetMethod.IsDeclaredReadOnly); - Assert.True(getProperty(s2, "P1").GetMethod.IsEffectivelyReadOnly); + Assert.True(getProperty(s2, "P1").GetMethod.IsReadOnly); - Assert.False(getProperty(s2, "P2").GetMethod.IsDeclaredReadOnly); - Assert.True(getProperty(s2, "P2").GetMethod.IsEffectivelyReadOnly); + Assert.True(getProperty(s2, "P2").GetMethod.IsReadOnly); - Assert.False(getProperty(s2, "P3").SetMethod.IsDeclaredReadOnly); - Assert.True(getProperty(s2, "P3").SetMethod.IsEffectivelyReadOnly); + Assert.True(getProperty(s2, "P3").SetMethod.IsReadOnly); - Assert.False(getProperty(s2, "P4").GetMethod.IsDeclaredReadOnly); - Assert.False(getProperty(s2, "P4").GetMethod.IsEffectivelyReadOnly); - Assert.False(getProperty(s2, "P4").SetMethod.IsDeclaredReadOnly); - Assert.False(getProperty(s2, "P4").SetMethod.IsEffectivelyReadOnly); + Assert.False(getProperty(s2, "P4").GetMethod.IsReadOnly); + Assert.False(getProperty(s2, "P4").SetMethod.IsReadOnly); - Assert.False(getEvent(s2, "E").AddMethod.IsDeclaredReadOnly); - Assert.True(getEvent(s2, "E").AddMethod.IsEffectivelyReadOnly); - Assert.False(getEvent(s2, "E").RemoveMethod.IsDeclaredReadOnly); - Assert.True(getEvent(s2, "E").RemoveMethod.IsEffectivelyReadOnly); + Assert.True(getEvent(s2, "E").AddMethod.IsReadOnly); + Assert.True(getEvent(s2, "E").RemoveMethod.IsReadOnly); static IMethodSymbol getMethod(INamedTypeSymbol symbol, string name) => (IMethodSymbol)symbol.GetMembers(name).Single(); static IPropertySymbol getProperty(INamedTypeSymbol symbol, string name) => (IPropertySymbol)symbol.GetMembers(name).Single(); diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index 9454747f5d437..312318f1d8f86 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,6 +1,5 @@ *REMOVED*Microsoft.CodeAnalysis.Operations.IEventAssignmentOperation.EventReference.get -> Microsoft.CodeAnalysis.Operations.IEventReferenceOperation -Microsoft.CodeAnalysis.IMethodSymbol.IsDeclaredReadOnly.get -> bool -Microsoft.CodeAnalysis.IMethodSymbol.IsEffectivelyReadOnly.get -> bool +Microsoft.CodeAnalysis.IMethodSymbol.IsReadOnly.get -> bool Microsoft.CodeAnalysis.Operations.IVariableDeclarationOperation.IgnoredDimensions.get -> System.Collections.Immutable.ImmutableArray abstract Microsoft.CodeAnalysis.Compilation.ClassifyCommonConversion(Microsoft.CodeAnalysis.ITypeSymbol source, Microsoft.CodeAnalysis.ITypeSymbol destination) -> Microsoft.CodeAnalysis.Operations.CommonConversion abstract Microsoft.CodeAnalysis.Compilation.ContainsSymbolsWithName(string name, Microsoft.CodeAnalysis.SymbolFilter filter = Microsoft.CodeAnalysis.SymbolFilter.TypeAndMember, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> bool diff --git a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs index 2da434fa6e9dc..09a438f49ff15 100644 --- a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs @@ -118,17 +118,10 @@ public interface IMethodSymbol : ISymbol IMethodSymbol ConstructedFrom { get; } /// - /// Indicates whether the method is declared readonly, i.e. - /// whether 'this' is readonly in the scope of the method. - /// See also + /// Indicates whether the method is readonly, i.e. + /// whether 'this' is 'ref readonly' in the scope of the method. /// - bool IsDeclaredReadOnly { get; } - - /// - /// Indicates whether the method is effectively readonly, - /// by either the method or the containing type being marked readonly. - /// - bool IsEffectivelyReadOnly { get; } + bool IsReadOnly { get; } /// /// Get the original definition of this symbol. If this symbol is derived from another diff --git a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb index cd2e19fe9791f..25b868e5491f7 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb @@ -100,20 +100,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property - - ''' - ''' Always returns false because the 'readonly members' feature is not available in VB. - ''' - Private ReadOnly Property IMethodSymbol_IsDeclaredReadOnly As Boolean Implements IMethodSymbol.IsDeclaredReadOnly - Get - Return False - End Get - End Property - ''' ''' Always returns false because the 'readonly members' feature is not available in VB. ''' - Private ReadOnly Property IMethodSymbol_IsEffectivelyReadOnly As Boolean Implements IMethodSymbol.IsEffectivelyReadOnly + Private ReadOnly Property IMethodSymbol_IsReadOnly As Boolean Implements IMethodSymbol.IsReadOnly Get Return False End Get diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs index 5ecf731072f02..8b156ac82f9f8 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs @@ -405,7 +405,7 @@ public override bool IsExtern get { return false; } } - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => false; internal override ObsoleteAttributeData ObsoleteAttributeData { diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs index 7e696b03f207b..d9069d099bf1d 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs @@ -118,7 +118,7 @@ public override bool IsVirtual get { return false; } } - public override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => false; public override ImmutableArray Locations { diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs index 437d1cf11cb20..85fe2f63c5007 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedMethodSymbol.cs @@ -25,9 +25,7 @@ public WrappedMethodSymbol(IMethodSymbol methodSymbol, bool canImplementImplicit public IMethodSymbol ConstructedFrom => _symbol.ConstructedFrom; - public bool IsDeclaredReadOnly => _symbol.IsDeclaredReadOnly; - - public bool IsEffectivelyReadOnly => _symbol.IsEffectivelyReadOnly; + public bool IsReadOnly => _symbol.IsReadOnly; public ImmutableArray ExplicitInterfaceImplementations { diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs index ede9b5126d753..c440086bb2949 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationAbstractMethodSymbol.cs @@ -38,8 +38,7 @@ protected CodeGenerationAbstractMethodSymbol( public abstract ImmutableArray TypeParameters { get; } public abstract ImmutableArray Parameters { get; } public abstract IMethodSymbol ConstructedFrom { get; } - public abstract bool IsDeclaredReadOnly { get; } - public abstract bool IsEffectivelyReadOnly { get; } + public abstract bool IsReadOnly { 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 b0e262ff9f88c..8c3504d2d68a6 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationConstructedMethodSymbol.cs @@ -70,9 +70,7 @@ public override ImmutableArray Parameters public override IMethodSymbol ConstructedFrom => _constructedFrom; - public override bool IsDeclaredReadOnly => _constructedFrom.IsDeclaredReadOnly; - - public override bool IsEffectivelyReadOnly => _constructedFrom.IsEffectivelyReadOnly; + public override bool IsReadOnly => _constructedFrom.IsReadOnly; public override IMethodSymbol OverriddenMethod => // TODO(cyrusn): Construct this. diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs index 798ada261035d..3ac4c6d2ba05c 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationMethodSymbol.cs @@ -86,9 +86,7 @@ public override ImmutableArray TypeArguments public override IMethodSymbol ConstructedFrom => this; - public override bool IsDeclaredReadOnly => throw ExceptionUtilities.Unreachable; - - public override bool IsEffectivelyReadOnly => throw ExceptionUtilities.Unreachable; + public override bool IsReadOnly => throw ExceptionUtilities.Unreachable; public override IMethodSymbol OverriddenMethod => null; From 8cb41d192450e642ef1be5e0c7696b8c4b7edeb0 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Mon, 1 Apr 2019 18:28:49 -0700 Subject: [PATCH 08/12] Fix IsReadOnly API for reduced extension methods. Test ref readonly ref properties. --- .../CSharp/Portable/Symbols/MethodSymbol.cs | 4 +- .../Symbols/ReducedExtensionMethodSymbol.cs | 5 +- .../Semantics/ReadOnlyStructsTests.cs | 120 +++++++++++++++++- .../Core/Portable/Symbols/IMethodSymbol.cs | 2 +- 4 files changed, 125 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index e40d673dce428..99c9991392ef2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -304,7 +304,7 @@ internal virtual bool IsExplicitInterfaceImplementation /// /// Indicates whether the method is declared readonly, i.e. - /// whether 'this' is readonly in the scope of the method. + /// whether the 'this' receiver parameter is 'ref readonly'. /// See also /// internal abstract bool IsDeclaredReadOnly { get; } @@ -315,7 +315,7 @@ internal virtual bool IsExplicitInterfaceImplementation /// internal bool IsEffectivelyReadOnly => (IsDeclaredReadOnly || ContainingType?.IsReadOnly == true) && IsValidReadOnlyTarget; - protected bool IsValidReadOnlyTarget => !IsStatic && ContainingType.IsStructType() && MethodKind != MethodKind.Constructor; + protected virtual bool IsValidReadOnlyTarget => !IsStatic && ContainingType.IsStructType() && MethodKind != MethodKind.Constructor; /// /// Returns interface methods explicitly implemented by this method. diff --git a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs index b53733ef2482e..ad03f0c621fd9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs @@ -373,8 +373,9 @@ internal override bool IsExplicitInterfaceImplementation get { return false; } } - // extension methods are static and therefore not readonly - internal override bool IsDeclaredReadOnly => false; + internal override bool IsDeclaredReadOnly => _reducedFrom.Parameters[0].RefKind == RefKind.In; + + protected override bool IsValidReadOnlyTarget => true; public override ImmutableArray ExplicitInterfaceImplementations { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index 6b24223c3e801..aa94b446ffa7a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -1022,12 +1022,37 @@ public readonly event Action E { add {} remove {} } public readonly struct S2 { public void M1() {} + public static void M2() {} + public int P1 { get; } public int P2 => 42; public int P3 { set {} } public static int P4 { get; set; } public event Action E { add {} remove {} } } + +public static class C +{ + static void M1(this S1 s1) {} + static void M2(this ref S1 s1) {} + static void M3(this in S1 s1) {} + static void M4(this S2 s2) {} + static void M5(this ref S2 s2) {} + static void M6(this in S2 s2) {} + + static void Test() + { + var s1 = new S1(); + s1.M1(); + s1.M2(); + s1.M3(); + + var s2 = new S2(); + s2.M4(); + s2.M5(); + s2.M6(); + } +} "; Compilation comp = CreateCompilation(csharp); var s1 = (INamedTypeSymbol)comp.GetSymbolsWithName("S1").Single(); @@ -1049,11 +1074,11 @@ public event Action E { add {} remove {} } Assert.False(getProperty(s1, "P5").SetMethod.IsReadOnly); Assert.True(getEvent(s1, "E").AddMethod.IsReadOnly); - Assert.True(getEvent(s1, "E").RemoveMethod.IsReadOnly); var s2 = comp.GetMember("S2"); Assert.True(getMethod(s2, "M1").IsReadOnly); + Assert.False(getMethod(s2, "M2").IsReadOnly); Assert.True(getProperty(s2, "P1").GetMethod.IsReadOnly); @@ -1072,6 +1097,99 @@ public event Action E { add {} remove {} } static IEventSymbol getEvent(INamedTypeSymbol symbol, string name) => (IEventSymbol)symbol.GetMembers(name).Single(); } + [Fact] + public void ReadOnlyMembers_ExtensionMethods_SemanticModel() + { + var csharp = @" +public struct S1 {} +public readonly struct S2 {} + +public static class C +{ + static void M1(this S1 s1) {} + static void M2(this ref S1 s1) {} + static void M3(this in S1 s1) {} + static void M4(this S2 s2) {} + static void M5(this ref S2 s2) {} + static void M6(this in S2 s2) {} + + static void Test() + { + var s1 = new S1(); + s1.M1(); + s1.M2(); + s1.M3(); + + var s2 = new S2(); + s2.M4(); + s2.M5(); + s2.M6(); + } +} +"; + Compilation comp = CreateCompilation(csharp); + + var c = comp.GetMember("C.Test"); + var testMethodSyntax = (MethodDeclarationSyntax)c.DeclaringSyntaxReferences.Single().GetSyntax(); + + var semanticModel = comp.GetSemanticModel(testMethodSyntax.SyntaxTree); + var statements = testMethodSyntax.Body.Statements; + + testStatement(statements[1], false); + testStatement(statements[2], false); + testStatement(statements[3], true); + + testStatement(statements[5], false); + testStatement(statements[6], false); + testStatement(statements[7], true); + + void testStatement(StatementSyntax statementSyntax, bool expected) + { + var expressionStatement = (ExpressionStatementSyntax)statementSyntax; + var invocationExpression = (InvocationExpressionSyntax)expressionStatement.Expression; + + var symbol = (MethodSymbol)semanticModel.GetSymbolInfo(invocationExpression.Expression).Symbol; + Assert.Equal(expected, symbol.IsDeclaredReadOnly); + Assert.Equal(expected, symbol.IsEffectivelyReadOnly); + Assert.Equal(expected, ((IMethodSymbol)symbol).IsReadOnly); + } + } + + [Fact] + public void ReadOnlyMembers_RefReturningProperty() + { + var csharp = @" +public struct S1 +{ + private static int i = 0; + + public ref int P1 => ref i; + public readonly ref int P2 => ref i; + public ref readonly int P3 => ref i; + public readonly ref readonly int P4 => ref i; +} +"; + var comp = CreateCompilation(csharp); + + var s1 = comp.GetMember("S1"); + + check(s1.GetProperty("P1"), true, false, false); + check(s1.GetProperty("P2"), true, false, true); + check(s1.GetProperty("P3"), false, true, false); + check(s1.GetProperty("P4"), false, true, true); + + static void check(PropertySymbol property, bool returnsByRef, bool returnsByRefReadonly, bool isReadOnly) + { + Assert.Equal(returnsByRef, property.ReturnsByRef); + Assert.Equal(returnsByRefReadonly, property.ReturnsByRefReadonly); + + Assert.True(property.IsReadOnly); + Assert.Equal(isReadOnly, property.GetMethod.IsDeclaredReadOnly); + Assert.Equal(isReadOnly, property.GetMethod.IsEffectivelyReadOnly); + Assert.Equal(isReadOnly, ((IMethodSymbol)property.GetMethod).IsReadOnly); + } + } + [Fact] public void ReadOnlyClass() { diff --git a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs index 09a438f49ff15..fd939a8d75985 100644 --- a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs @@ -119,7 +119,7 @@ public interface IMethodSymbol : ISymbol /// /// Indicates whether the method is readonly, i.e. - /// whether 'this' is 'ref readonly' in the scope of the method. + /// i.e. whether the 'this' receiver parameter is 'ref readonly'. /// bool IsReadOnly { get; } From d42aa7ad0ee504e673c146b9707a10f89411a787 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 2 Apr 2019 11:23:30 -0700 Subject: [PATCH 09/12] Ensure that non-reduced extension methods are never 'readonly' --- .../CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index aa94b446ffa7a..db8d85c2e2a06 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -1149,9 +1149,15 @@ void testStatement(StatementSyntax statementSyntax, bool expected) var invocationExpression = (InvocationExpressionSyntax)expressionStatement.Expression; var symbol = (MethodSymbol)semanticModel.GetSymbolInfo(invocationExpression.Expression).Symbol; + var reducedFrom = symbol.ReducedFrom; + Assert.Equal(expected, symbol.IsDeclaredReadOnly); Assert.Equal(expected, symbol.IsEffectivelyReadOnly); Assert.Equal(expected, ((IMethodSymbol)symbol).IsReadOnly); + + Assert.False(reducedFrom.IsDeclaredReadOnly); + Assert.False(reducedFrom.IsEffectivelyReadOnly); + Assert.False(((IMethodSymbol)reducedFrom).IsReadOnly); } } From cc6fb9d8ff3a2a34bea3087edb9832dfaac7c780 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 2 Apr 2019 11:45:26 -0700 Subject: [PATCH 10/12] Update doc --- src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs index fd939a8d75985..fb28b65a1b379 100644 --- a/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/IMethodSymbol.cs @@ -120,6 +120,8 @@ public interface IMethodSymbol : ISymbol /// /// Indicates whether the method is readonly, i.e. /// i.e. whether the 'this' receiver parameter is 'ref readonly'. + /// Returns true for readonly instance methods and accessors + /// and for reduced extension methods with a 'this in' parameter. /// bool IsReadOnly { get; } From 2b1fc7f205972b22b22a69b9483876a6e19a8fa9 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 2 Apr 2019 12:12:09 -0700 Subject: [PATCH 11/12] Reduced extension methods are not declared readonly, they're effectively readonly. --- src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs | 4 ++-- .../Portable/Symbols/ReducedExtensionMethodSymbol.cs | 4 ++-- .../Test/Semantic/Semantics/ReadOnlyStructsTests.cs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index 2f094219480d5..3a3156c984eda 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -313,9 +313,9 @@ internal virtual bool IsExplicitInterfaceImplementation /// Indicates whether the method is effectively readonly, /// by either the method or the containing type being marked readonly. /// - internal bool IsEffectivelyReadOnly => (IsDeclaredReadOnly || ContainingType?.IsReadOnly == true) && IsValidReadOnlyTarget; + internal virtual bool IsEffectivelyReadOnly => (IsDeclaredReadOnly || ContainingType?.IsReadOnly == true) && IsValidReadOnlyTarget; - protected virtual bool IsValidReadOnlyTarget => !IsStatic && ContainingType.IsStructType() && MethodKind != MethodKind.Constructor; + protected bool IsValidReadOnlyTarget => !IsStatic && ContainingType.IsStructType() && MethodKind != MethodKind.Constructor; /// /// Returns interface methods explicitly implemented by this method. diff --git a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs index ad03f0c621fd9..a734e643634d8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs @@ -373,9 +373,9 @@ internal override bool IsExplicitInterfaceImplementation get { return false; } } - internal override bool IsDeclaredReadOnly => _reducedFrom.Parameters[0].RefKind == RefKind.In; + internal override bool IsDeclaredReadOnly => false; - protected override bool IsValidReadOnlyTarget => true; + internal override bool IsEffectivelyReadOnly => _reducedFrom.Parameters[0].RefKind == RefKind.In; public override ImmutableArray ExplicitInterfaceImplementations { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index db8d85c2e2a06..745f42aa11b0d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -1143,7 +1143,7 @@ static void Test() testStatement(statements[6], false); testStatement(statements[7], true); - void testStatement(StatementSyntax statementSyntax, bool expected) + void testStatement(StatementSyntax statementSyntax, bool isEffectivelyReadOnly) { var expressionStatement = (ExpressionStatementSyntax)statementSyntax; var invocationExpression = (InvocationExpressionSyntax)expressionStatement.Expression; @@ -1151,10 +1151,10 @@ void testStatement(StatementSyntax statementSyntax, bool expected) var symbol = (MethodSymbol)semanticModel.GetSymbolInfo(invocationExpression.Expression).Symbol; var reducedFrom = symbol.ReducedFrom; - Assert.Equal(expected, symbol.IsDeclaredReadOnly); - Assert.Equal(expected, symbol.IsEffectivelyReadOnly); - Assert.Equal(expected, ((IMethodSymbol)symbol).IsReadOnly); + Assert.Equal(isEffectivelyReadOnly, symbol.IsEffectivelyReadOnly); + Assert.Equal(isEffectivelyReadOnly, ((IMethodSymbol)symbol).IsReadOnly); + Assert.False(symbol.IsDeclaredReadOnly); Assert.False(reducedFrom.IsDeclaredReadOnly); Assert.False(reducedFrom.IsEffectivelyReadOnly); Assert.False(((IMethodSymbol)reducedFrom).IsReadOnly); From 86afb13cd12716c0180b230bbfdb2f02716e4ed1 Mon Sep 17 00:00:00 2001 From: Rikki Gibson Date: Tue, 2 Apr 2019 16:51:29 -0700 Subject: [PATCH 12/12] Remove unused copy of extension methods test source --- .../Semantics/ReadOnlyStructsTests.cs | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs index 745f42aa11b0d..a76581d75a53e 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs @@ -1030,29 +1030,6 @@ public int P3 { set {} } public static int P4 { get; set; } public event Action E { add {} remove {} } } - -public static class C -{ - static void M1(this S1 s1) {} - static void M2(this ref S1 s1) {} - static void M3(this in S1 s1) {} - static void M4(this S2 s2) {} - static void M5(this ref S2 s2) {} - static void M6(this in S2 s2) {} - - static void Test() - { - var s1 = new S1(); - s1.M1(); - s1.M2(); - s1.M3(); - - var s2 = new S2(); - s2.M4(); - s2.M5(); - s2.M6(); - } -} "; Compilation comp = CreateCompilation(csharp); var s1 = (INamedTypeSymbol)comp.GetSymbolsWithName("S1").Single();