diff --git a/src/CSharpGuidelinesAnalyzer/CSharpGuidelinesAnalyzer.Test/Specs/Maintainability/DoNotUseOptionalParameterWithDefaultValueNullSpecs.cs b/src/CSharpGuidelinesAnalyzer/CSharpGuidelinesAnalyzer.Test/Specs/Maintainability/DoNotUseOptionalParameterWithDefaultValueNullSpecs.cs index 455cd41..9d70a14 100644 --- a/src/CSharpGuidelinesAnalyzer/CSharpGuidelinesAnalyzer.Test/Specs/Maintainability/DoNotUseOptionalParameterWithDefaultValueNullSpecs.cs +++ b/src/CSharpGuidelinesAnalyzer/CSharpGuidelinesAnalyzer.Test/Specs/Maintainability/DoNotUseOptionalParameterWithDefaultValueNullSpecs.cs @@ -215,6 +215,75 @@ await VerifyGuidelineDiagnosticAsync(source, "Optional parameter 'p' of type 'ValueTask?' has default value 'null'"); } + [Fact] + internal async Task When_method_implicitly_implements_interface_method_it_must_be_skipped() + { + // Arrange + ParsedSourceCode source = new TypeSourceCodeBuilder() + .WithReferenceToExternalAssemblyFor(@" + public interface I + { + void M(string s = null); + } + ") + .InGlobalScope(@" + class C : I + { + public void M(string s = null) => throw null; + } + ") + .Build(); + + // Act and assert + await VerifyGuidelineDiagnosticAsync(source); + } + + [Fact] + internal async Task When_method_explicitly_implements_interface_method_it_must_be_skipped() + { + // Arrange + ParsedSourceCode source = new TypeSourceCodeBuilder() + .WithReferenceToExternalAssemblyFor(@" + public interface I + { + void M(string s = null); + } + ") + .InGlobalScope(@" + class C : I + { + void I.M(string s = null) => throw null; + } + ") + .Build(); + + // Act and assert + await VerifyGuidelineDiagnosticAsync(source); + } + + [Fact] + internal async Task When_method_overrides_base_method_it_must_be_skipped() + { + // Arrange + ParsedSourceCode source = new TypeSourceCodeBuilder() + .WithReferenceToExternalAssemblyFor(@" + public abstract class B + { + public virtual void M(string s = null) => throw null; + } + ") + .InGlobalScope(@" + class C : B + { + public override void M(string s = null) => throw null; + } + ") + .Build(); + + // Act and assert + await VerifyGuidelineDiagnosticAsync(source); + } + protected override DiagnosticAnalyzer CreateAnalyzer() { return new DoNotUseOptionalParameterWithDefaultValueNullAnalyzer(); diff --git a/src/CSharpGuidelinesAnalyzer/CSharpGuidelinesAnalyzer/Rules/Maintainability/DoNotUseOptionalParameterWithDefaultValueNullAnalyzer.cs b/src/CSharpGuidelinesAnalyzer/CSharpGuidelinesAnalyzer/Rules/Maintainability/DoNotUseOptionalParameterWithDefaultValueNullAnalyzer.cs index 12fe527..38b2643 100644 --- a/src/CSharpGuidelinesAnalyzer/CSharpGuidelinesAnalyzer/Rules/Maintainability/DoNotUseOptionalParameterWithDefaultValueNullAnalyzer.cs +++ b/src/CSharpGuidelinesAnalyzer/CSharpGuidelinesAnalyzer/Rules/Maintainability/DoNotUseOptionalParameterWithDefaultValueNullAnalyzer.cs @@ -82,7 +82,8 @@ private static void AnalyzeParameter(SymbolAnalysisContext context, [NotNull] [I { var parameter = (IParameterSymbol)context.Symbol; - if (parameter.IsOptional && parameter.HasExplicitDefaultValue && parameter.ExplicitDefaultValue == null && + if (parameter.IsOptional && parameter.HasExplicitDefaultValue && parameter.ExplicitDefaultValue == null && !parameter.ContainingSymbol.IsOverride && + !parameter.ContainingSymbol.IsInterfaceImplementation() && !HasCallerArgumentExpressionAttribute(parameter, callerArgumentExpressionAttributeType)) { if (parameter.Type.IsOrImplementsIEnumerable() || IsTask(parameter.Type, taskTypes))