Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void HandlePropertyReference(IPropertyReferenceOperation op)
case OperationKind.PropertyReference:
{
var propertyRef = (IPropertyReferenceOperation)instance;
if (CanUpgrade(propertyRef.Property, false))
if (CanUpgrade(propertyRef.Property))
{
RecordVirtualDispatch(propertyRef.Property, targetMethod);
}
Expand Down Expand Up @@ -182,7 +182,7 @@ public void HandleInvocation(IInvocationOperation op)
case OperationKind.PropertyReference:
{
var propertyRef = (IPropertyReferenceOperation)instance;
if (CanUpgrade(propertyRef.Property, false))
if (CanUpgrade(propertyRef.Property))
{
RecordVirtualDispatch(propertyRef.Property, op.TargetMethod);
}
Expand Down Expand Up @@ -343,7 +343,7 @@ public void HandlePropertyInitializer(IPropertyInitializerOperation op)
{
foreach (var property in op.InitializedProperties)
{
if (CanUpgrade(property, false))
if (CanUpgrade(property))
{
RecordAssignment(property, valueType);
}
Expand Down Expand Up @@ -399,7 +399,7 @@ public void HandleReturn(IReturnOperation op)
{
if (methodSym.AssociatedSymbol is IPropertySymbol propertySym)
{
if (CanUpgrade(propertySym, false))
if (CanUpgrade(propertySym))
{
var valueTypes = GetValueTypes(op.ReturnedValue);
foreach (var valueType in valueTypes)
Expand Down Expand Up @@ -725,15 +725,16 @@ private bool CanUpgrade(IFieldSymbol fieldSym)
/// <summary>
/// Trivial reject for properties that can't be upgraded in order to avoid wasted work.
/// </summary>
private bool CanUpgrade(IPropertySymbol propSym, bool setter)
private bool CanUpgrade(IPropertySymbol propSym)
{
var m = setter ? propSym.SetMethod! : propSym.GetMethod!;
var m = propSym.GetMethod!;

return _checkVisibility!(m)
&& !m.IsImplementationOfAnyInterfaceMember()
&& !m.IsOverride
&& !m.IsVirtual
&& m.PartialDefinitionPart == null;
&& m.PartialDefinitionPart == null &&
m.DeclaredAccessibility >= (propSym.SetMethod?.DeclaredAccessibility ?? default);
}

private void RecordVirtualDispatch(IFieldSymbol field, IMethodSymbol target) => VirtualDispatchFields.GetOrAdd(field, _ => PooledConcurrentSet<IMethodSymbol>.GetInstance(SymbolEqualityComparer.Default)).Add(target);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.

using System.Threading.Tasks;
using System.Diagnostics.CodeAnalysis;
using Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
using Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
Microsoft.NetCore.Analyzers.Performance.UseConcreteTypeAnalyzer,
Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
Expand Down Expand Up @@ -427,6 +426,45 @@ public void M(C1 c1, IFoo f)
await TestCSAsync(Source, $"dotnet_code_quality.CA1859.api_surface = public,private,internal");
}

[Fact]
[WorkItem(50362, "https://github.com/dotnet/roslyn-analyzers/issues/50362")]
public static async Task ShouldNotTrigger_PropertyWithSetterMoreAccessibleThanGetter()
{
await TestCSAsync(@"
using System;
using System.Threading.Tasks;

public class Class1
{
public I Prop { private get; set; } = new Impl1();

void M()
{
Prop.M();
Prop.MyProperty = 1;
Prop[1] = 1;
Prop.Evt += (s, e) => { };
}
}

public interface I
{
int MyProperty { get; set; }
int this[int i] { get; set; }
event EventHandler Evt;
void M();
}

public class Impl1 : I
{
public int MyProperty { get; set; }
public int this[int i] { get => i; set { } }
public event EventHandler Evt;
public void M() { }
}
");
}

[Theory]
[InlineData("private", "", true)]
[InlineData("private", "private", true)]
Expand Down Expand Up @@ -1502,7 +1540,7 @@ private void M(ValueTuple<Action> vt)
await TestCSAsync(Source);
}

private static async Task TestCSAsync(string source, params DiagnosticResult[] diagnosticResults)
private static async Task TestCSAsync([StringSyntax("C#-test")] string source, params DiagnosticResult[] diagnosticResults)
{
var test = new VerifyCS.Test
{
Expand All @@ -1515,7 +1553,7 @@ private static async Task TestCSAsync(string source, params DiagnosticResult[] d
await test.RunAsync();
}

private static async Task TestCSAsync(string source, string editorConfigText, params DiagnosticResult[] diagnosticResults)
private static async Task TestCSAsync([StringSyntax("C#-test")] string source, string editorConfigText, params DiagnosticResult[] diagnosticResults)
{
var test = new VerifyCS.Test
{
Expand Down