Skip to content

Fix CA1856 and CA2252 for missed attributes when multiple interfaces implemented #7692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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 @@ -147,28 +147,36 @@
if (methodSymbol.ExplicitInterfaceImplementations
.FirstOrDefault(methodSymbol.IsImplementationOfInterfaceMember) is { } explicitInterfaceMethod)
{
CheckParameters(methodSymbol.Parameters, explicitInterfaceMethod.Parameters);
ReportIfAttributeNotImplementedFromParent(methodSymbol.Parameters, explicitInterfaceMethod.Parameters);
}
else if (methodSymbol.OverriddenMethod is not null)
{
CheckParameters(methodSymbol.Parameters, methodSymbol.OverriddenMethod.Parameters);
ReportIfAttributeNotImplementedFromParent(methodSymbol.Parameters, methodSymbol.OverriddenMethod.Parameters);
}
else if (methodSymbol.IsImplementationOfAnyImplicitInterfaceMember(out IMethodSymbol interfaceMethodSymbol))
else
{
CheckParameters(methodSymbol.Parameters, interfaceMethodSymbol.Parameters);
foreach (var interfaceMethodSymbol in methodSymbol.GetImplementedImplicitInterfaceMembers<IMethodSymbol>())
{
if (ReportIfAttributeNotImplementedFromParent(methodSymbol.Parameters, interfaceMethodSymbol.Parameters))

Check failure on line 160 in src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Source-Build ())

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs#L160

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs(160,25): error CS0029: (NETCORE_ENGINEERING_TELEMETRY=Build) Cannot implicitly convert type 'void' to 'bool'

Check failure on line 160 in src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Debug)

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs#L160

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs(160,25): error CS0029: (NETCORE_ENGINEERING_TELEMETRY=Build) Cannot implicitly convert type 'void' to 'bool'

Check failure on line 160 in src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Release)

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs#L160

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs(160,25): error CS0029: (NETCORE_ENGINEERING_TELEMETRY=Build) Cannot implicitly convert type 'void' to 'bool'

Check failure on line 160 in src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs#L160

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs(160,25): error CS0029: (NETCORE_ENGINEERING_TELEMETRY=Build) Cannot implicitly convert type 'void' to 'bool'
{
break;
}
}
}

void CheckParameters(ImmutableArray<IParameterSymbol> parameters, ImmutableArray<IParameterSymbol> baseParameters)
void ReportIfAttributeNotImplementedFromParent(ImmutableArray<IParameterSymbol> parameters, ImmutableArray<IParameterSymbol> baseParameters)
{
if (constantExpectedContext.ValidatesAttributeImplementedFromParent(parameters, baseParameters, out var diagnostics))
{
return;
return false;

Check failure on line 171 in src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Source-Build ())

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs#L171

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs(171,21): error CS0127: (NETCORE_ENGINEERING_TELEMETRY=Build) Since 'ReportIfAttributeNotImplementedFromParent(ImmutableArray<IParameterSymbol>, ImmutableArray<IParameterSymbol>)' returns void, a return keyword must not be followed by an object expression

Check failure on line 171 in src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Debug)

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs#L171

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs(171,21): error CS0127: (NETCORE_ENGINEERING_TELEMETRY=Build) Since 'ReportIfAttributeNotImplementedFromParent(ImmutableArray<IParameterSymbol>, ImmutableArray<IParameterSymbol>)' returns void, a return keyword must not be followed by an object expression

Check failure on line 171 in src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs#L171

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs(171,21): error CS0127: (NETCORE_ENGINEERING_TELEMETRY=Build) Since 'ReportIfAttributeNotImplementedFromParent(ImmutableArray<IParameterSymbol>, ImmutableArray<IParameterSymbol>)' returns void, a return keyword must not be followed by an object expression
}

foreach (var diagnostic in diagnostics)
{
context.ReportDiagnostic(diagnostic);
}

return true;

Check failure on line 179 in src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Source-Build ())

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs#L179

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs(179,17): error CS0127: (NETCORE_ENGINEERING_TELEMETRY=Build) Since 'ReportIfAttributeNotImplementedFromParent(ImmutableArray<IParameterSymbol>, ImmutableArray<IParameterSymbol>)' returns void, a return keyword must not be followed by an object expression

Check failure on line 179 in src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Debug)

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs#L179

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Performance/ConstantExpectedAnalyzer.cs(179,17): error CS0127: (NETCORE_ENGINEERING_TELEMETRY=Build) Since 'ReportIfAttributeNotImplementedFromParent(ImmutableArray<IParameterSymbol>, ImmutableArray<IParameterSymbol>)' returns void, a return keyword must not be followed by an object expression
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,7 +533,7 @@ private void ProcessPropertyOrMethodAttributes(SymbolAnalysisContext context,
}
}

if (propertyOrMethodSymbol.IsImplementationOfAnyImplicitInterfaceMember(out ISymbol baseInterfaceMember))
foreach (var baseInterfaceMember in propertyOrMethodSymbol.GetImplementedImplicitInterfaceMembers<ISymbol>())
{
if (SymbolIsAnnotatedAsPreview(baseInterfaceMember, requiresPreviewFeaturesSymbols, previewFeatureAttributeSymbol))
{
Expand All @@ -555,6 +555,8 @@ private void ProcessPropertyOrMethodAttributes(SymbolAnalysisContext context,
ReportDiagnosticWithCustomMessageIfItExists(context, baseInterfaceMember, propertyOrMethodSymbol, requiresPreviewFeaturesSymbols,
ImplementsPreviewMethodRule, ImplementsPreviewMethodRuleWithCustomMessage, propertyOrMethodSymbol.Name, baseInterfaceMemberName);
}

break;
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ public interface ITest2<T>
{{
T Method(T operand1, [ConstantExpected] T operand2);
}}
public interface ITest3<T>
{{
T Method(T operand1, T operand2);
}}
public abstract class AbstractTest<T>
{{
public abstract T Method2(T operand1, [ConstantExpected] T operand2);
Expand All @@ -145,6 +149,20 @@ public class Generic : AbstractTest<{type}>, ITest<{type}>, ITest2<{type}>
{type} ITest2<{type}>.Method({type} operand1, {{|#1:{type} operand2|}}) => throw new NotImplementedException();
public override {type} Method2({type} operand1, {{|#2:{type} operand2|}}) => throw new NotImplementedException();
}}

public class GenericExplicit : ITest<{type}>, ITest3<{type}>
{{
public {type} Method({type} operand1, {type} operand2) => throw new NotImplementedException();
{type} ITest<{type}>.Method({type} operand1, {{|#3:{type} operand2|}}) => throw new NotImplementedException();
}}
public class Generic13 : ITest<{type}>, ITest3<{type}>
{{
public {type} Method({type} operand1, {{|#4:{type} operand2|}}) => throw new NotImplementedException();
}}
public class Generic31 : ITest3<{type}>, ITest<{type}>
{{
public {type} Method({type} operand1, {{|#5:{type} operand2|}}) => throw new NotImplementedException();
}}
}}
";
await TestCSAsync(csInput,
Expand All @@ -153,7 +171,13 @@ await TestCSAsync(csInput,
VerifyCS.Diagnostic(ConstantExpectedAnalyzer.CA1857.AttributeExpectedRule)
.WithLocation(1),
VerifyCS.Diagnostic(ConstantExpectedAnalyzer.CA1857.AttributeExpectedRule)
.WithLocation(2));
.WithLocation(2),
VerifyCS.Diagnostic(ConstantExpectedAnalyzer.CA1857.AttributeExpectedRule)
.WithLocation(3),
VerifyCS.Diagnostic(ConstantExpectedAnalyzer.CA1857.AttributeExpectedRule)
.WithLocation(4),
VerifyCS.Diagnostic(ConstantExpectedAnalyzer.CA1857.AttributeExpectedRule)
.WithLocation(5));
}

[Theory]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,54 @@ public void Foo()
await test.RunAsync();
}


[Fact]
public async Task TestInterfaceMethodDoubleImplementations()
{
var csInput = @"
using System.Runtime.Versioning; using System;
namespace Preview_Feature_Scratch
{
class Program : IProgram, IProgram2
{
static void Main(string[] args)
{
}

public void {|#0:Foo|}()
{
throw new NotImplementedException();
}
}

class Program2 : IProgram2, IProgram
{
public void {|#1:Foo|}()
{
throw new NotImplementedException();
}
}

public interface IProgram
{
[RequiresPreviewFeatures]
public void Foo();
}

public interface IProgram2
{
public void Foo();
}
}

";

var test = TestCS(csInput);
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewMethodRule).WithLocation(0).WithArguments("Foo", "IProgram.Foo", DetectPreviewFeatureAnalyzer.DefaultURL));
test.ExpectedDiagnostics.Add(VerifyCS.Diagnostic(DetectPreviewFeatureAnalyzer.ImplementsPreviewMethodRule).WithLocation(1).WithArguments("Foo", "IProgram.Foo", DetectPreviewFeatureAnalyzer.DefaultURL));
await test.RunAsync();
}

[Fact]
public async Task TestDelegate()
{
Expand Down
28 changes: 5 additions & 23 deletions src/Utilities/Compiler/Extensions/ISymbolExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -471,27 +471,13 @@
public static bool IsImplementationOfAnyImplicitInterfaceMember<TSymbol>(this ISymbol symbol)
where TSymbol : ISymbol
{
if (symbol.ContainingType != null)
{
foreach (INamedTypeSymbol interfaceSymbol in symbol.ContainingType.AllInterfaces)
{
foreach (var interfaceMember in interfaceSymbol.GetMembers().OfType<TSymbol>())
{
if (IsImplementationOfInterfaceMember(symbol, interfaceMember))
{
return true;
}
}
}
}

return false;
return GetImplementedImplicitInterfaceMembers(symbol).Any();

Check failure on line 474 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Source-Build ())

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L474

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(474,20): error CS0411: (NETCORE_ENGINEERING_TELEMETRY=Build) The type arguments for method 'ISymbolExtensions.GetImplementedImplicitInterfaceMembers<TSymbol>(ISymbol)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Check failure on line 474 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Debug)

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L474

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(474,20): error CS0411: (NETCORE_ENGINEERING_TELEMETRY=Build) The type arguments for method 'ISymbolExtensions.GetImplementedImplicitInterfaceMembers<TSymbol>(ISymbol)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Check failure on line 474 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Release)

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L474

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(474,20): error CS0411: (NETCORE_ENGINEERING_TELEMETRY=Build) The type arguments for method 'ISymbolExtensions.GetImplementedImplicitInterfaceMembers<TSymbol>(ISymbol)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Check failure on line 474 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Release)

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L474

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(474,20): error CS0411: (NETCORE_ENGINEERING_TELEMETRY=Build) The type arguments for method 'ISymbolExtensions.GetImplementedImplicitInterfaceMembers<TSymbol>(ISymbol)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

Check failure on line 474 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L474

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(474,20): error CS0411: (NETCORE_ENGINEERING_TELEMETRY=Build) The type arguments for method 'ISymbolExtensions.GetImplementedImplicitInterfaceMembers<TSymbol>(ISymbol)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
}

/// <summary>
/// Checks if a given symbol implements an interface member implicitly
/// Checks if a given symbol implements an interface member implicitly and interface member satisfies given predicate
/// </summary>
public static bool IsImplementationOfAnyImplicitInterfaceMember<TSymbol>(this ISymbol symbol, out TSymbol interfaceMember)
public static IEnumerable<TSymbol> GetImplementedImplicitInterfaceMembers<TSymbol>(this ISymbol symbol)
where TSymbol : ISymbol
{
if (symbol.ContainingType != null)
Expand All @@ -500,17 +486,13 @@
{
foreach (var baseInterfaceMember in interfaceSymbol.GetMembers().OfType<TSymbol>())
{
if (IsImplementationOfInterfaceMember(symbol, baseInterfaceMember))
if (IsImplementationOfInterfaceMember(symbol, baseInterfaceMember) && predicate(symbol))

Check failure on line 489 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Source-Build ())

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L489

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(489,95): error CS0103: (NETCORE_ENGINEERING_TELEMETRY=Build) The name 'predicate' does not exist in the current context

Check failure on line 489 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Debug)

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L489

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(489,95): error CS0103: (NETCORE_ENGINEERING_TELEMETRY=Build) The name 'predicate' does not exist in the current context

Check failure on line 489 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Release)

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L489

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(489,95): error CS0103: (NETCORE_ENGINEERING_TELEMETRY=Build) The name 'predicate' does not exist in the current context

Check failure on line 489 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI (Ubuntu Release)

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L489

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(489,95): error CS0103: (NETCORE_ENGINEERING_TELEMETRY=Build) The name 'predicate' does not exist in the current context

Check failure on line 489 in src/Utilities/Compiler/Extensions/ISymbolExtensions.cs

View check run for this annotation

Azure Pipelines / roslyn-analyzers-CI

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs#L489

src/Utilities/Compiler/Extensions/ISymbolExtensions.cs(489,95): error CS0103: (NETCORE_ENGINEERING_TELEMETRY=Build) The name 'predicate' does not exist in the current context
{
interfaceMember = baseInterfaceMember;
return true;
yield return baseInterfaceMember;
}
}
}
}

interfaceMember = default;
return false;
}

public static bool IsImplementationOfInterfaceMember(this ISymbol symbol, [NotNullWhen(returnValue: true)] ISymbol? interfaceMember)
Expand Down
Loading