diff --git a/src/Meziantou.Analyzer/Rules/DoNotUseToStringIfObjectAnalyzer.cs b/src/Meziantou.Analyzer/Rules/DoNotUseToStringIfObjectAnalyzer.cs index 387482a76..5116047b6 100644 --- a/src/Meziantou.Analyzer/Rules/DoNotUseToStringIfObjectAnalyzer.cs +++ b/src/Meziantou.Analyzer/Rules/DoNotUseToStringIfObjectAnalyzer.cs @@ -87,6 +87,11 @@ public void AnalyzeInvocation(OperationAnalysisContext context) internal static void AnalyzeAdd(OperationAnalysisContext context) { var operation = (IBinaryOperation)context.Operation; + + // Only the built-in string concatenation calls ToString on the operands + if (operation.OperatorKind is not BinaryOperatorKind.Add || operation.OperatorMethod is not null) + return; + if (!operation.Type.IsString()) return; diff --git a/tests/Meziantou.Analyzer.Test/Rules/DoNotUseToStringIfObjectAnalyzerTests.cs b/tests/Meziantou.Analyzer.Test/Rules/DoNotUseToStringIfObjectAnalyzerTests.cs index 43476bb0e..6125f2970 100755 --- a/tests/Meziantou.Analyzer.Test/Rules/DoNotUseToStringIfObjectAnalyzerTests.cs +++ b/tests/Meziantou.Analyzer.Test/Rules/DoNotUseToStringIfObjectAnalyzerTests.cs @@ -678,6 +678,25 @@ public struct A{ } return test.RunAsync(); } + [Fact] + public Task UserDefinedOperatorReturningString() + { + var test = CreateTest(); + test.TestCode = """ + var a = new Foo(); + _ = a - a; + _ = a + a; + + sealed class Foo + { + public static string operator -(Foo x, Foo y) => ""; + public static string operator +(Foo x, Foo y) => ""; + } + """; + + return test.RunAsync(); + } + [Fact] public Task SealedRecord_Concat() {